it-roy-ru.com

Как обнаружить событие кнопки "Назад" в браузере - Cross Browser

Как вы определите, действительно ли пользователь нажал кнопку «Назад» в браузере? 

Как вы применяете использование кнопки возврата внутри страницы в одностраничном веб-приложении, используя систему #URL

Почему же кнопки браузера не запускают свои собственные события !?

147
Xarus

(Примечание: в соответствии с отзывами Шарки, я включил код для обнаружения пробелов)

Итак, я часто сталкивался с этими вопросами в SO, и недавно я столкнулся с проблемой управления функциональностью кнопки «назад». После нескольких дней поиска лучшего решения для моего приложения (одностраничный с хэш-навигацией) я нашел простую, кросс-браузерную, безбиблиотечную систему для обнаружения кнопки «назад».

Большинство людей рекомендуют использовать:

window.onhashchange = function() {
 //blah blah blah
}

Однако эта функция также будет вызываться, когда пользователь использует элемент на странице, который изменяет хэш расположения. Не лучший пользовательский опыт, когда ваш пользователь нажимает и страница переходит вперед или назад.

Чтобы дать вам общее представление о моей системе, я заполняю массив предыдущими хэшами, когда мой пользователь перемещается по интерфейсу. Это выглядит примерно так:

function updateHistory(curr) {
    window.location.lasthash.Push(window.location.hash);
    window.location.hash = curr;
}

Довольно прямо вперед. Я делаю это для обеспечения кросс-браузерной поддержки, а также поддержки старых браузеров. Просто передайте новый хеш функции, и он сохранит его для вас, а затем изменит хеш (который затем заносится в историю браузера).

Я также использую кнопку возврата на странице, которая перемещает пользователя между страницами с помощью массива lasthash. Это выглядит так:

function goBack() {
    window.location.hash = window.location.lasthash[window.location.lasthash.length-1];
    //blah blah blah
    window.location.lasthash.pop();
}

Так что это переместит пользователя обратно к последнему хешу и удалит этот последний хеш из массива (у меня сейчас нет кнопки вперед).

Так. Как определить, использовал ли пользователь мою кнопку возврата на странице или кнопку браузера?

Сначала я посмотрел на window.onbeforeunload, но безрезультатно - он вызывается, только если пользователь собирается менять страницы. Этого не происходит в одностраничном приложении, использующем хеш-навигацию.

Итак, после еще нескольких копаний я увидел рекомендации по установке переменной-флага. Проблема с этим в моем случае состоит в том, что я попытался бы установить его, но, поскольку все является асинхронным, он не всегда будет установлен вовремя для оператора if в изменении хеша. .onMouseDown не всегда вызывался при щелчке, и добавление его в onclick никогда не вызывало бы его достаточно быстро.

Это когда я начал смотреть на разницу между document и window. Мое окончательное решение состояло в том, чтобы установить флаг, используя document.onmouseover, и отключить его, используя document.onmouseleave.

Что происходит, когда пользовательская мышь находится внутри области документа (читай: отображаемая страница, но исключая фрейм браузера), мой логический параметр установлен на true. Как только мышь покидает область документа, логическое значение переходит на false.

Таким образом, я могу изменить свой window.onhashchange на:

window.onhashchange = function() {
    if (window.innerDocClick) {
        window.innerDocClick = false;
    } else {
        if (window.location.hash != '#undefined') {
            goBack();
        } else {
            history.pushState("", document.title, window.location.pathname);
            location.reload();
        }
    }
}

Вы отметите проверку для #undefined. Это потому, что если в моем массиве нет доступной истории, он возвращает undefined. Я использую это, чтобы спросить пользователя, хотят ли они уйти, используя событие window.onbeforeunload.

Итак, вкратце, и для людей, которые не обязательно используют кнопку возврата на странице или массив для хранения истории:

document.onmouseover = function() {
    //User's mouse is inside the page.
    window.innerDocClick = true;
}

document.onmouseleave = function() {
    //User's mouse has left the page.
    window.innerDocClick = false;
}

window.onhashchange = function() {
    if (window.innerDocClick) {
        //Your own in-page mechanism triggered the hash change
    } else {
        //Browser back button was clicked
    }
}

И там у вас есть это. простой, состоящий из трех частей способ обнаружения использования кнопки «Назад» и элементов на странице в отношении хеш-навигации.

Правка:

Чтобы гарантировать, что пользователь не использует backspace для запуска события back, вы также можете включить следующее (благодаря @thetoolman на этот вопрос ):

$(function(){
    /*
     * this swallows backspace keys on any non-input element.
     * stops backspace -> back
     */
    var rx = /INPUT|SELECT|TEXTAREA/i;

    $(document).bind("keydown keypress", function(e){
        if( e.which == 8 ){ // 8 == backspace
            if(!rx.test(e.target.tagName) || e.target.disabled || e.target.readOnly ){
                e.preventDefault();
            }
        }
    });
});
134
Xarus

Вы можете попробовать popstate обработчик события, например:

window.addEventListener('popstate', function(event) {
    // The popstate event is fired each time when the current history entry changes.

    var r = confirm("You pressed a Back button! Are you sure?!");

    if (r == true) {
        // Call Back button programmatically as per user confirmation.
        history.back();
        // Uncomment below line to redirect to the previous page instead.
        // window.location = document.referrer // Note: IE11 is not supporting this.
    } else {
        // Stay on the current page.
        history.pushState(null, null, window.location.pathname);
    }

    history.pushState(null, null, window.location.pathname);

}, false);

Примечание. Для достижения наилучших результатов этот код следует загружать только на определенных страницах, где требуется реализовать логику, чтобы избежать любых других непредвиденных проблем.

Событие popstate запускается каждый раз, когда изменяется текущая запись истории (пользователь переходит в новое состояние). Это происходит, когда пользователь нажимает кнопки браузера «Назад» и «Вперед» или когда программно вызываются методы history.back(), history.forward(), history.go().

Свойство event.state является событием, равным объекту состояния истории.

Для синтаксиса jQuery оберните его (чтобы добавить даже слушателя после того, как документ будет готов):

(function($) {
  // Above code here.
})(jQuery);

Смотрите также: window.onpopstate при загрузке страницы


Смотрите также примеры в Одностраничные приложения и HTML5 pushState page:

<script>
// jQuery
$(window).on('popstate', function (e) {
    var state = e.originalEvent.state;
    if (state !== null) {
        //load content with ajax
    }
});

// Vanilla javascript
window.addEventListener('popstate', function (e) {
    var state = e.state;
    if (state !== null) {
        //load content with ajax
    }
});
</script>

Это должно быть совместимо с Chrome 5+, Firefox 4+, IE 10+, Safari 6+, Opera 11.5+ и аналогичными.

53
kenorb

Я довольно долго боролся с этим требованием и применил некоторые из приведенных выше решений для его реализации. Однако я наткнулся на наблюдение, и оно, похоже, работает в браузерах Chrome, Firefox и Safari + Android и iPhone. 

На странице загрузки:

window.history.pushState({page: 1}, "", "");

window.onpopstate = function(event) {

  // "event" object seems to contain value only when the back button is clicked
  // and if the pop state event fires due to clicks on a button
  // or a link it comes up as "undefined" 

  if(event){
    // Code to handle back button or prevent from navigation
  }
  else{
    // Continue user action through link or button
  }
}

Позвольте мне знать, если это помогает. Если что-то упустил, я буду рад понять.

11
Itzmeygu

В javascript тип навигации 2 означает, что браузер нажал кнопку «назад» или «вперед», и браузер фактически получает контент из кэша.

if(performance.navigation.type == 2)
{
    //Do your code here
}
7
Hasan Badshah

Браузер: https://jsfiddle.net/Limitlessisa/axt1Lqoz/

Для мобильного управления: https://jsfiddle.net/Limitlessisa/axt1Lqoz/show/

$(document).ready(function() {
  $('body').on('click touch', '#share', function(e) {
    $('.share').fadeIn();
  });
});

// geri butonunu yakalama
window.onhashchange = function(e) {
  var oldURL = e.oldURL.split('#')[1];
  var newURL = e.newURL.split('#')[1];

  if (oldURL == 'share') {
    $('.share').fadeOut();
    e.preventDefault();
    return false;
  }
  //console.log('old:'+oldURL+' new:'+newURL);
}
.share{position:fixed; display:none; top:0; left:0; width:100%; height:100%; background:rgba(0,0,0,.8); color:white; padding:20px;
<!DOCTYPE html>
<html>

<head>
    <title>Back Button Example</title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

</head>

<body style="text-align:center; padding:0;">
    <a href="#share" id="share">Share</a>
    <div class="share" style="">
        <h1>Test Page</h1>
        <p> Back button press please for control.</p>
    </div>
</body>

</html>

3
Limitless isa

Вот мой взгляд на это. Предполагается, что когда URL-адрес изменяется, но в пределах обнаруженной document щелчка нет, браузер возвращается (да или вперед). Клик пользователя сбрасывается через 2 секунды, чтобы это работало на страницах, которые загружают контент через Ajax:

(function(window, $) {
  var anyClick, consoleLog, debug, delay;
  delay = function(sec, func) {
    return setTimeout(func, sec * 1000);
  };
  debug = true;
  anyClick = false;
  consoleLog = function(type, message) {
    if (debug) {
      return console[type](message);
    }
  };
  $(window.document).click(function() {
    anyClick = true;
    consoleLog("info", "clicked");
    return delay(2, function() {
      consoleLog("info", "reset click state");
      return anyClick = false;
    });
  });
  return window.addEventListener("popstate", function(e) {
    if (anyClick !== true) {
      consoleLog("info", "Back clicked");
      return window.dataLayer.Push({
        event: 'analyticsEvent',
        eventCategory: 'test',
        eventAction: 'test'
      });
    }
  });
})(window, jQuery);
2
TomTom101

Мне удалось использовать некоторые ответы в этой теме и другие, чтобы они работали в IE и ​​Chrome/Edge. history.pushState для меня не поддерживается в IE11.

if (history.pushState) {
    //Chrome and modern browsers
    history.pushState(null, document.title, location.href);
    window.addEventListener('popstate', function (event) {
        history.pushState(null, document.title, location.href);
    });
}
else {
    //IE
    history.forward();
}
1
Arsalan Siddiqui

Document.mouseover не работает для IE и FireFox . Однако я пробовал это:

$(document).ready(function () {
  setInterval(function () {
    var $sample = $("body");
    if ($sample.is(":hover")) {
      window.innerDocClick = true;
    } else {
      window.innerDocClick = false;
    }
  });

});

window.onhashchange = function () {
  if (window.innerDocClick) {
    //Your own in-page mechanism triggered the hash change
  } else {
    //Browser back or forward button was pressed
  }
};

Это работает для Chrome и IE, а не для FireFox. Все еще работаю, чтобы получить право FireFox. Любой простой способ обнаружить нажатие кнопки «Назад/Вперед» в браузере приветствуется, не только в JQuery, но и в AngularJS или обычном Javascript. 

1
Dhruv Gupta
if (window.performance && window.performance.navigation.type == window.performance.navigation.TYPE_BACK_FORWARD) {
  alert('hello world');
}

Это единственное решение, которое сработало для меня (это не одностраничный сайт). Работает с Chrome, Firefox и Safari.

0
escanxr

Я решил эту проблему, отслеживая исходное событие, которое вызвало переменную hashchange (будь то пролистывание, щелчок или колесо), чтобы событие не было ошибочно принято за простую посадку на странице, и использовал дополнительный флаг в каждом из моих событий привязки. Браузер не установит флаг снова на false при нажатии кнопки «Назад»:

var evt = null,
canGoBackToThePast = true;

$('#next-slide').on('click touch', function(e) {
    evt = e;
    canGobackToThePast = false;
    // your logic (remember to set the 'canGoBackToThePast' flag back to 'true' at the end of it)
}
0
user1025495
 <input style="display:none" id="__pageLoaded" value=""/>


 $(document).ready(function () {
        if ($("#__pageLoaded").val() != 1) {

            $("#__pageLoaded").val(1);


        } else {
            shared.isBackLoad = true;
            $("#__pageLoaded").val(1);  

            // Call any function that handles your back event

        }
    });

Приведенный выше код работал для меня. В мобильных браузерах, когда пользователь нажимал кнопку «Назад», мы хотели восстановить состояние страницы в соответствии с его предыдущим посещением.

0
Ashwin

Это определенно будет работать (для обнаружения нажатия кнопки назад)

$(window).on('popstate', function(event) {
 alert("pop");
});
0
rohan parab

Видеть это:

history.pushState(null, null, location.href);
    window.onpopstate = function () {
        history.go(1);
    };

работает нормально ...

0
Jorge Rocha