Come rilevare l’evento del pulsante Indietro del browser – Cross Browser

Come si rileva in modo definitivo se l’utente ha premuto o meno il pulsante Indietro nel browser?

Come si impone l’uso di un pulsante back in-page all’interno di un’applicazione Web a pagina singola utilizzando un sistema #URL ?

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

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

Quindi, ho visto queste domande frequentemente su SO, e di recente ho incontrato il problema del controllo della funzionalità del pulsante back da solo. Dopo alcuni giorni di ricerca della migliore soluzione per la mia applicazione (Single-Page con Hash Navigation), ho trovato un semplice sistema di cross-browser e senza libreria per il rilevamento del pulsante Indietro.

La maggior parte delle persone consiglia di utilizzare:

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

Tuttavia, questa funzione verrà chiamata anche quando un utente utilizza un 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 profilo generale del mio sistema, sto riempiendo un array con hash precedenti mentre il mio utente si muove 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, così come 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 verrà poi inserito nella cronologia del browser).

lasthash anche un pulsante back in-page che sposta l’utente tra le pagine utilizzando l’array lasthash . Sembra questo:

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

In questo modo l’utente tornerà all’ultimo hash e rimuoverà l’ultimo hash dall’array (al momento non ho alcun pulsante avanti).

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

In un primo momento ho guardato a window.onbeforeunload , ma senza alcun risultato – che viene chiamato solo se l’utente sta per cambiare le pagine. Ciò non accade in un’applicazione a pagina singola utilizzando la navigazione hash.

Quindi, dopo un po ‘di ricerche, ho visto dei consigli per provare a impostare una variabile flag. Il problema con questo nel mio caso è che proverei ad impostarlo, ma poiché tutto è asincrono, non dovrebbe essere sempre impostato in tempo per l’istruzione if nella modifica dell’hash. .onMouseDown non è stato sempre chiamato in click, e l’aggiunta ad un onclick non lo farebbe mai abbastanza veloce.

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

Quello che succede è che mentre il mouse dell’utente si trova all’interno dell’area del documento (leggi: la pagina visualizzata, ma escludendo la cornice del browser), il mio booleano è impostato su true . Non appena il mouse lascia l’area del documento, il booleano diventa false .

In questo modo, posso cambiare il mio window.onhashchange in:

 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’è una cronologia disponibile nel mio array, restituisce undefined . Lo uso per chiedere all’utente se vuole uscire usando un evento window.onbeforeunload .

Quindi, in breve, e per le persone che non utilizzano necessariamente un pulsante back in-page o un array per archiviare 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 posteriore rispetto agli elementi in-page per quanto riguarda la navigazione hash.

MODIFICARE:

Per garantire che l’utente non utilizzi backspace per triggersre l’evento back, puoi anche includere 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(); } } }); }); 

Puoi provare il gestore di eventi popstate , ad esempio:

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

Nota: per ottenere risultati ottimali, è necessario caricare questo codice solo su pagine specifiche in cui si desidera implementare la logica per evitare altri problemi imprevisti.

L’evento popstate viene triggersto ogni volta che cambia la voce della cronologia corrente (l’utente passa a un nuovo stato). Ciò accade quando l’utente fa clic sui pulsanti Indietro / Avanti del browser o quando vengono chiamati in modo cronologico i metodi history.back() , history.forward() , history.go() .

event.state è la proprietà dell’evento è uguale all’object dello stato della cronologia.

Per la syntax jQuery, avvolgila (per aggiungere un ascoltatore anche dopo che il documento è pronto):

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

Vedi anche: window.onpopstate al caricamento della pagina


Vedi anche gli esempi su app a pagina singola e pagina pushState HTML5 :

  

Questo dovrebbe essere compatibile con Chrome 5+, Firefox 4+, IE 10+, Safari 6+, Opera 11.5+ e simili.

Ho avuto a che fare con questo requisito da un po ‘di tempo e ho preso alcune delle soluzioni sopra per implementarlo. Tuttavia, mi sono imbattuto in un’osservazione e sembra funzionare su browser Chrome, Firefox e Safari + Android e iPhone

A caricamento pagina:

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

Fammi sapere se questo aiuta. Se mi manca qualcosa, sarò felice di capire.

Browser: https://jsfiddle.net/Limitlessisa/axt1Lqoz/

Per il controllo mobile: 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; 
    Back Button Example    Share    

Ecco il mio modo di prenderlo. Il presupposto è che quando l’URL cambia ma non vi è alcun clic all’interno del document rilevato, è un browser indietro (sì o avanti). Un clic utente viene ripristinato dopo 2 secondi per far funzionare le pagine che caricano il contenuto tramite 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); 

Document.mouseover non funziona con IE e FireFox. Tuttavia ho provato questo:

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

Questo funziona per Chrome e IE e non per FireFox. Ancora lavorando per ottenere FireFox giusto. Qualsiasi modo semplice per rilevare il clic del pulsante Indietro / Avanti del browser è benvenuto, non particolarmente in JQuery ma anche in AngularJS o in Javascript semplice.

L’ho risolto tenendo traccia dell’evento originale che ha triggersto l’ hashchange (sia esso uno swipe, un clic o una ruota), in modo che l’evento non venisse scambiato per un semplice landing-on-page e utilizzando una flag aggiuntiva in ciascuna delle mie associazioni di eventi. Il browser non imposterà nuovamente la bandiera su false quando si preme il pulsante Indietro:

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

Ho provato le opzioni di cui sopra ma nessuno di loro sta funzionando per me. Ecco la soluzione

 if(window.event) { if(window.event.clientX < 40 && window.event.clientY < 0) { alert("Browser back button is clicked..."); } else { alert("Browser refresh button is clicked..."); } } 

Fare riferimento a questo link http://www.codeproject.com/Articles/696526/Solution-to-Browser-Back-Button-Click-Event-Handli per ulteriori dettagli