Come rilevare l'evento del pulsante Indietro del browser - Cross Browser


219

Come si rileva definitivamente se l'utente ha premuto il pulsante Indietro nel browser?

Come imponi l'uso di un pulsante Indietro in-page all'interno di un'applicazione web a pagina singola usando un #URLsistema?

Perché mai i pulsanti indietro del browser non attivano i propri eventi !?


2
Vorrei che gli eventi di navigazione (indietro / avanti) venissero aggiunti qualche volta. Finora si tratta di qualcosa che si trova nelle opere developer.mozilla.org/en-US/docs/Web/API/…
llaaalu,

Risposte:


184

(Nota: secondo il feedback di Sharky, ho incluso il codice per rilevare i backspaces)

Quindi, ho visto queste domande frequentemente su SO, e recentemente ho incontrato il problema del controllo della funzionalità del pulsante Indietro da solo. Dopo alcuni giorni di ricerca della migliore soluzione per la mia applicazione (Pagina singola con navigazione hash), ho trovato un sistema semplice, senza browser e senza libreria per il rilevamento del pulsante Indietro.

Molte persone raccomandano di usare:

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

Tuttavia, questa funzione verrà chiamata anche quando un utente utilizza l'elemento in-page che modifica l'hash della posizione. Non la migliore esperienza utente quando l'utente fa clic e la pagina va avanti o indietro.

Per darti un quadro generale del mio sistema, sto riempiendo un array con hash precedenti mentre il mio utente si sposta attraverso l'interfaccia. Sembra qualcosa del genere:

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

Abbastanza diretto. Lo faccio per garantire il supporto cross-browser, nonché il supporto per i browser più vecchi. Passa semplicemente il nuovo hash alla funzione e lo memorizzerà per te e poi cambierà l'hash (che viene quindi inserito nella cronologia del browser).

Uso anche un pulsante Indietro in-page che sposta l'utente tra le pagine usando l' lasthasharray. Sembra così:

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

Quindi, questo riporterà l'utente all'ultimo hash e rimuoverà l'ultimo hash dall'array (al momento non ho un pulsante avanti).

Così. Come faccio a rilevare se un utente ha utilizzato o meno il mio pulsante Indietro in-page o il pulsante del browser?

In un primo momento ho guardato window.onbeforeunload, ma senza successo - che viene chiamato solo se l'utente sta per cambiare pagina. Ciò non accade in un'applicazione a pagina singola che utilizza la navigazione hash.

Quindi, dopo qualche altro scavo, ho visto dei consigli per provare a impostare una variabile flag. Il problema con questo nel mio caso è che proverei a impostarlo, ma poiché tutto è asincrono, non sarebbe sempre impostato in tempo per l'istruzione if nella modifica dell'hash. .onMouseDownnon veniva sempre chiamato in clic e aggiungerlo a un clic non lo avrebbe mai attivato abbastanza velocemente.

Questo è quando ho iniziato a guardare la differenza tra document, e window. La mia soluzione finale era impostare il flag usando document.onmouseovere disabilitarlo usando document.onmouseleave.

Quello che succede è che mentre il mouse dell'utente è all'interno dell'area del documento (leggi: la pagina renderizzata, ma escluso il frame del browser), il mio valore booleano è impostato su true. Non appena il mouse lascia l'area del documento, il booleano si sposta su false.

In questo modo, posso cambiare il mio window.onhashchangein:

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();
        }
    }
}

Noterai il controllo per #undefined. Questo perché se non c'è cronologia disponibile nel mio array, ritorna undefined. Lo uso per chiedere all'utente se desidera uscire utilizzando un window.onbeforeunloadevento.

Quindi, in breve, e per le persone che non utilizzano necessariamente un pulsante Indietro in-page o un array per memorizzare la cronologia:

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
    }
}

E il gioco è fatto. un modo semplice in tre parti per rilevare l'utilizzo del pulsante Indietro rispetto agli elementi in-page per quanto riguarda la navigazione dell'hash.

MODIFICARE:

Per garantire che l'utente non utilizzi backspace per attivare l'evento back, è possibile includere anche quanto segue (Grazie a @thetoolman su questa domanda ):

$(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();
            }
        }
    });
});

5
+1 bella idea, ma penso che questo fallirà se l'utente usa qualunque scorciatoia da tastiera per "back" (tasto backspace su firefox) mentre il suo mouse è nella finestra del browser
Sharky

3
Lo farò - Sono in ufficio in questo momento comunque :) (EDIT: Fatto ora)
Xarus

7
Che dire del cellulare (ad es
Ipad

5
Che dire degli eventi di scorrimento dal trackpad in MAC. Potrebbe essere catturato anche quello?
Sriganesh Navaneethakrishnan,

6
Come posso differenziare i pulsanti avanti e indietro?
Mr_Perfect,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.