(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ą lasthash
tablicy. 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. .onMouseDown
nie 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.onmouseover
i 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.onhashchange
na:
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.onbeforeunload
zdarzenia.
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();
}
}
});
});