(Примечание: в соответствии с обратной связью Шарки я включил код для обнаружения обратных пространств)
Итак, я часто видел эти вопросы на SO и недавно столкнулся с проблемой управления кнопкой возврата функциональность. После нескольких дней поиска наилучшего решения для моего приложения (Single-страница с Hash Navigation), я придумал простую, кросс-браузерную, библиотечную систему для обнаружения кнопки «Назад».
Большинство людей рекомендуют использовать:
window.onhashchange = function() {
//blah blah blah
}
Однако эта функция также вызывается, когда пользователь использует элемент in-page, который изменяет хэш местоположения. Не лучший пользовательский интерфейс, когда пользователь нажимает, а страница идет назад или вперед.
Чтобы дать вам общую схему моей системы, я заполняю массив предыдущими хэшами, когда мой пользователь перемещается по интерфейс. Это выглядит примерно так:
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
.
Что происходит, когда мышь пользователя находится внутри области документа (читайте: отображаемая страница, но исключая рама браузера), мое значение boolean равно 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
}
}
И вот она у вас есть. простой, трехчастный способ обнаружения использования кнопки обратной связи и элементов на странице в отношении хеш-навигации.
EDIT:
Чтобы гарантировать, что пользователь не использует обратное пространство для вы можете включить следующее: (Спасибо @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();
}
}
});
});