(Uwaga: zgodnie z opinią Sharky, dołączyłem kod do wykrywania backspace)
Tak więc często widziałem te pytania na SO, a ostatnio sam miałem problem z kontrolowaniem funkcji przycisku Wstecz. Po kilku dniach poszukiwania najlepszego rozwiązania dla mojej aplikacji (jednostronicowa z nawigacją mieszającą), opracowałem prosty, bezobsługowy system wykrywania w przeglądarce dla różnych przeglądarek.
Większość osób zaleca używanie:
window.onhashchange = function() {
//blah blah blah
}
Jednak ta funkcja będzie również wywoływana, gdy użytkownik użyje elementu na stronie, który zmienia skrót lokalizacji. Nie jest to najlepsze doświadczenie użytkownika, gdy użytkownik klika, a strona przewija się do tyłu lub do przodu.
Aby dać ogólny zarys mojego systemu, wypełniam tablicę poprzednimi hashami, gdy mój użytkownik porusza się po interfejsie. Wygląda to mniej więcej tak:
function updateHistory(curr) {
window.location.lasthash.push(window.location.hash);
window.location.hash = curr;
}
Całkiem prosto. Robię to, aby zapewnić obsługę wielu przeglądarek, a także obsługę starszych przeglądarek. Po prostu przekaż nowy skrót do funkcji, a on zapisze go dla ciebie, a następnie zmieni skrót (który jest następnie zapisywany w historii przeglądarki).
Korzystam również z przycisku Wstecz na stronie, który przenosi użytkownika między stronami za pomocą lasthashtablicy. To wygląda tak:
function goBack() {
window.location.hash = window.location.lasthash[window.location.lasthash.length-1];
//blah blah blah
window.location.lasthash.pop();
}
Spowoduje to przeniesienie użytkownika z powrotem do ostatniego skrótu i usunięcie tego ostatniego skrótu z tablicy (w tej chwili nie mam przycisku przewijania).
Więc. Jak wykryć, czy użytkownik użył przycisku Wstecz na stronie lub przycisku przeglądarki?
Na początku patrzyłem window.onbeforeunload, ale bezskutecznie - jest to wywoływane tylko wtedy, gdy użytkownik zamierza zmienić strony. Nie dzieje się tak w przypadku aplikacji jednostronicowej korzystającej z funkcji skrótu.
Po dłuższym kopaniu zobaczyłem zalecenia dotyczące próby ustawienia zmiennej flagowej. Problem w tym przypadku polega na tym, że spróbuję to ustawić, ale ponieważ wszystko jest asynchroniczne, nie zawsze będzie ono ustawione na czas na zmianę instrukcji if w haszowaniu. .onMouseDownnie zawsze było wywoływane kliknięciem, a dodanie go do kliknięcia nigdy nie uruchomiłoby go wystarczająco szybko.
To wtedy zacząłem patrzeć na różnicę między document, a window. Moim ostatecznym rozwiązaniem było ustawienie flagi za pomocą document.onmouseoveri wyłączenie jej za pomocą document.onmouseleave.
Co się dzieje, gdy mysz użytkownika znajduje się w obszarze dokumentu (czytaj: renderowana strona, ale z wyłączeniem ramki przeglądarki), moja wartość logiczna jest ustawiona na true. Gdy tylko mysz opuści obszar dokumentu, wartość logiczna zmienia się na false.
W ten sposób mogę zmienić moje window.onhashchangena:
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();
}
}
}
Zauważysz czek na #undefined. Wynika to z faktu, że jeśli w mojej tablicy nie ma dostępnej historii, funkcja zwraca wartość undefined. Używam tego, aby zapytać użytkownika, czy chce odejść za pomocą window.onbeforeunloadzdarzenia.
Krótko mówiąc, dla osób, które niekoniecznie używają przycisku Wstecz na stronie lub tablicy do przechowywania historii:
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
}
}
I masz to. prosty, trzyczęściowy sposób wykrywania użycia przycisku Wstecz w porównaniu z elementami na stronie w odniesieniu do nawigacji hash.
EDYTOWAĆ:
Aby mieć pewność, że użytkownik nie użyje backspace, aby wywołać zdarzenie back, możesz również dołączyć następujące (Dzięki @thetoolman na to pytanie ):
$(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();
}
}
});
});