Esiste un evento di caricamento cross-browser quando si fa clic sul pulsante Indietro?


185

Per tutti i principali browser (eccetto IE), l' onloadevento JavaScript non si attiva quando la pagina viene caricata a seguito di un'operazione del pulsante Indietro: si attiva solo quando la pagina viene caricata per la prima volta.

Qualcuno può indicarmi un codice cross-browser di esempio (Firefox, Opera, Safari, IE, ...) che risolve questo problema? Conosco l' pageshowevento di Firefox, ma sfortunatamente né Opera né Safari lo implementano.


6
Questo non è un problema: consente di caricare rapidamente la pagina Web quando l'utente preme il pulsante Indietro. Vedi la mia risposta qui sotto per i dettagli. Le soluzioni alternative suggerite qui rendono la pagina Web più fastidiosa per l'utente, poiché la navigazione avanti / indietro è più lenta.
Nickolay,

2
@romkyns: il tuo commento non è correlato a questa domanda. Quando i browser non ripristinano lo stato JS / DOM, generano l'evento load.
Nickolay,

Il pulsante Indietro della cronologia di iOS 5+ risolto qui stackoverflow.com/a/12652160/1090395
Mladen Janjetovic

Risposte:


117

Ragazzi, ho scoperto che JQuery ha un solo effetto: la pagina viene ricaricata quando si preme il pulsante Indietro. Questo non ha nulla a che fare con " pronto ".

Come funziona? Bene, JQuery aggiunge un listener di eventi onunload .

// http://code.jquery.com/jquery-latest.js
jQuery(window).bind("unload", function() { // ...

Per impostazione predefinita, non fa nulla. Ma in qualche modo questo sembra innescare un ricaricamento in Safari, Opera e Mozilla, indipendentemente dal contenuto del gestore eventi.

[ modifica (Nickolay) : ecco perché funziona in questo modo: webkit.org , developer.mozilla.org . Leggi quegli articoli (o il mio sommario in una risposta separata di seguito) e considera se hai davvero bisogno di fare questo e rallenta il caricamento della tua pagina per i tuoi utenti.]

Non ci credi? Prova questo:

<body onunload=""><!-- This does the trick -->
<script type="text/javascript">
    alert('first load / reload');
    window.onload = function(){alert('onload')};
</script>
<a href="http://stackoverflow.com">click me, then press the back button</a>
</body>

Vedrai risultati simili quando usi JQuery.

Potresti voler confrontare con questo senza onunload

<body><!-- Will not reload on back button -->
<script type="text/javascript">
    alert('first load / reload');
    window.onload = function(){alert('onload')};
</script>
<a href="http://stackoverflow.com">click me, then press the back button</a>
</body>

1
Molto bello .. anche se questa è una caratteristica / bug non documentato e potrebbe semplicemente smettere di funzionare nelle versioni future del browser, ma è comunque interessante.
Wadih M.,

3
Funziona anche così (non dimenticare la parte onunload = "", altrimenti non funzionerà su ff3): <body onload = "alert ('onload');" onunload = "">
Wadih M.

3
Questo perché il browser presume che la pagina sia invariabile se ha un onunloadgestore (la pagina ha già distrutto tutto; perché memorizzarla nella cache?).
Casey Chu,

14
La risposta sembra non funzionare nei browser moderni - controllato nell'ultimo Chrome e Opera
Andrew,

10
non funziona in Safari Safari ... per favore, deselezionalo come risposta
xus

74

Alcuni browser moderni (Firefox, Safari e Opera, ma non Chrome) supportano la speciale cache "indietro / avanti" (la chiamerò bfcache, che è un termine inventato da Mozilla), coinvolta quando l'utente naviga indietro. A differenza della normale cache (HTTP), acquisisce lo stato completo della pagina (incluso lo stato di JS, DOM). Ciò consente di ricaricare la pagina più velocemente e esattamente come l'utente l'ha lasciata.

L' loadevento non dovrebbe attivarsi quando la pagina viene caricata da questo bfcache. Ad esempio, se hai creato la tua UI nel gestore "load" e l'evento "load" è stato generato una volta sul caricamento iniziale e la seconda volta quando la pagina veniva ricaricata dalla bfcache, la pagina sarebbe finita con elementi dell'interfaccia utente duplicati.

Questo è anche il motivo per cui l'aggiunta del gestore "Unload" interrompe l'archiviazione della pagina in bfcache (rendendo così più lento il ritorno a) - il gestore Unload potrebbe eseguire attività di pulizia, che potrebbero lasciare la pagina in uno stato non realizzabile.

Per le pagine che devono sapere quando vengono trasferite / tornare a, Firefox 1.5+ e la versione di Safari con la correzione del bug 28758 supportano eventi speciali chiamati "pageshow" e "pagehide".

Riferimenti:


È molto bello. Attualmente mi trovo in una situazione in cui le mie manipolazioni di dom non sembrano essere salvate nella bfcache. Ci sono situazioni in cui te lo aspetti?
Benson,

1
@Benson: i possibili motivi per cui Firefox non salverà la tua pagina in bfcache sono elencati nella pagina dev.mo a cui mi sono collegato. Non credo sia possibile salvare la pagina su bfcache, ma non è possibile salvare un determinato stato DOM.
Nickolay,

Nickolay, ho la tua riluttanza a forzare una ricarica e annullare il buon lavoro svolto da bfcache, ma c'è un altro modo per aggiornare la dom della pagina in bfcache? Ad esempio, considera la situazione in cui vado da una pagina che ha un elenco di messaggi a uno di essi e quando torno "indietro" voglio che l'indicatore di lettura / non letto cambi. Come è possibile farlo senza ricaricare la pagina?
Greg,

@Greg: intendi come sviluppatore che controlla la pagina? Lancia una richiesta Ajax da un ascoltatore di "pageshow".
Nickolay,

Qualche idea su come usare jQuery E ottenere un supporto rapido per bfcache?
Alex Black,

31

Ho riscontrato un problema che il mio js non stava eseguendo quando l'utente aveva fatto clic su avanti o indietro. Per prima cosa ho deciso di fermare la memorizzazione nella cache del browser, ma questo non sembrava essere il problema. Il mio javascript era impostato per essere eseguito dopo che tutte le librerie ecc. Erano state caricate. Ho controllato questi con l'evento readyStateChange.

Dopo alcuni test ho scoperto che il readyState di un elemento in una pagina in cui è stato fatto clic su back non è "caricato" ma "completo". L'aggiunta || element.readyState == 'complete'alla mia dichiarazione condizionale ha risolto i miei problemi.

Ho pensato di condividere le mie scoperte, speriamo che possano aiutare qualcun altro.

Modifica per completezza

Il mio codice era il seguente:

script.onreadystatechange(function(){ 
   if(script.readyState == 'loaded' || script.readyState == 'complete') {
      // call code to execute here.
   } 
});

Nell'esempio di codice sopra la variabile di script c'era un elemento di script appena creato che era stato aggiunto al DOM.


7
Dove l'hai aggiunto? E come hai fatto a sparare qualcosa dopo che l'utente ha risposto? Per favore, mostraci un po 'di codice!
Keerigan

Cosa intendi quando dici "la mia dichiarazione condizionale"?
Phillip Senn,

1
@Phillip Un'istruzione condizionale è un'istruzione if.
Brian Heese,

22

OK, ecco una soluzione finale basata sulla soluzione iniziale di ckramer e sull'esempio di palehorse che funziona in tutti i browser, incluso Opera. Se imposti history.navigationMode su 'compatibile', la funzione pronta di jQuery si attiverà sulle operazioni del pulsante Indietro in Opera e sugli altri principali browser.

Questa pagina contiene ulteriori informazioni .

Esempio:

history.navigationMode = 'compatible';
$(document).ready(function(){
  alert('test');
});

Ho provato questo in Opera 9.5, IE7, FF3 e Safari e funziona in tutti loro.


2
Ovviamente è passato un po 'di tempo (circa 5,5 anni) ma vale la pena notare che il tuo link è morto.
Jeff,

2
Questa soluzione non funziona per me. Ho questo problema nell'ultimo Firefox (45.0.1)
Armin

6

Non sono riuscito a far funzionare gli esempi sopra. Volevo semplicemente innescare un aggiornamento di alcune aree div modificate quando si torna alla pagina tramite il pulsante Indietro. Il trucco che ho usato era di impostare un campo di input nascosto (chiamato "bit sporco") su 1 non appena le aree div sono cambiate rispetto all'originale. Il campo di input nascosto mantiene effettivamente il suo valore quando clicco indietro, quindi onload posso verificare questo bit. Se è impostato, aggiorno la pagina (o semplicemente aggiorno i div). Sul caricamento originale, tuttavia, il bit non è impostato, quindi non perdo tempo a caricare la pagina due volte.

<input type='hidden' id='dirty'>

<script>
$(document).ready(function() {
  if ($('#dirty').val()) {
    // ... reload the page or specific divs only
  }
  // when something modifies a div that needs to be refreshed, set dirty=1
  $('#dirty').val('1');
});
</script>

E si innescherebbe correttamente ogni volta che ho fatto clic sul pulsante Indietro.


3
Mentre questo non funziona in Firefox, penso che sia un modo astuto per gestire la situazione in IE / Chrome in cui la persistenza del campo nascosto è molto utile. Ho usato il tuo trucco e anche l'evento "pageshow", quindi copro tutti i principali browser.
Magnus Smith,

Quale browser non funziona con pagine, come funziona?
Justin,

4

Se ricordo bene, l'aggiunta di un evento unload () significa che la pagina non può essere memorizzata nella cache (nella cache in avanti / indietro) - perché il suo stato cambia / può cambiare quando l'utente si allontana. Quindi - non è sicuro ripristinare lo stato dell'ultimo secondo della pagina quando si ritorna ad essa navigando attraverso l'oggetto della cronologia.


4

Ho pensato che questo sarebbe per "onunload", non per il caricamento della pagina, dal momento che non stiamo parlando di lanciare un evento quando si colpisce "Back"? $ document.ready () è per gli eventi desiderati al caricamento della pagina, indipendentemente da come si arriva a quella pagina (ad es. reindirizzamento, apertura diretta del browser all'URL, ecc.), non quando si fa clic su "Indietro", a meno che non si stia parlando su cosa sparare sulla pagina precedente quando si carica di nuovo. E non sono sicuro che la pagina non venga memorizzata nella cache poiché ho scoperto che lo sono ancora i Javascripts, anche quando $ document.ready () è incluso in essi. Abbiamo dovuto premere Ctrl + F5 durante la modifica dei nostri script che presentano questo evento ogni volta che li revisioniamo e vogliamo testare i risultati nelle nostre pagine.

$(window).unload(function(){ alert('do unload stuff here'); }); 

è ciò che vorresti per un evento onunload quando si preme "Indietro" e si scarica la pagina corrente e si attiva anche quando un utente chiude la finestra del browser. Sembrava più quello che si desiderava, anche se sono più numeroso delle risposte $ document.ready (). Fondamentalmente la differenza è tra un evento che si attiva sulla pagina corrente mentre si sta chiudendo o su quello che si carica quando si fa clic su "Indietro" durante il caricamento. Testato in IE 7 bene, non posso parlare per gli altri browser in quanto non sono ammessi dove siamo. Ma questa potrebbe essere un'altra opzione.


4

Posso confermare a ckramer che l'evento pronto di jQuery funziona in IE e FireFox. Ecco un esempio:

<html>
<head>
    <title>Test Page</title>
    <script src="http://code.jquery.com/jquery-latest.js" type="text/javascript"></script>
    <script type="text/javascript">
            $(document).ready(function () {
               var d = new Date();
               $('#test').html( "Hi at " + d.toString() );
            });
    </script>
</head>
<body>
    <div id="test"></div>
    <div>
        <a href="http://www.google.com">Go!</a>
    </div>
</body>
</html>

4

per le persone che non vogliono usare l'intera libreria jquery ho estratto l'implementazione in un codice separato. È grande solo 0,4 KB.

Puoi trovare il codice, insieme a un tutorial tedesco in questo wiki: http://www.easy-coding.de/wiki/html-ajax-und-co/onload-event-cross-browser-kompatibler-domcontentloaded.html


1
Il collegamento solitario è considerato una risposta scadente (vedi faq ) poiché non ha senso da solo e non è garantito che la risorsa target sia viva in futuro . Sarebbe preferibile includere qui le parti essenziali della risposta e fornire il collegamento come riferimento.
jk

3

L' evento pronto di jQuery è stato creato proprio per questo tipo di problema. Potresti voler approfondire l'implementazione per vedere cosa sta succedendo sotto le copertine.


6
Molto tempo dopo, readynon sembra essere attivato in Firefox, quando si utilizza il pulsante Indietro. Vedi anche la risposta di Nickolay .
Arjan,

2

Bill, oso rispondere alla tua domanda, tuttavia non sono sicuro al 100% delle mie ipotesi. Penso che altri browser IE quando portano l'utente a una pagina nella cronologia non solo caricheranno la pagina e le sue risorse dalla cache, ma ripristineranno anche l'intero stato DOM (lettura della sessione). IE non esegue il ripristino del DOM (o al momento del leasing) e quindi l'evento onload sembra essere necessario per una corretta reinizializzazione della pagina.


2

Ho provato la soluzione da Bill usando $ (documento). Già ... ma all'inizio non ha funzionato. Ho scoperto che se lo script viene inserito dopo la sezione HTML, non funzionerà. Se è la sezione head funzionerà, ma solo in IE. Lo script non funziona in Firefox.


1

OK, l'ho provato e funziona con Firefox 3, Safari 3.1.1 e IE7 ma non con Opera 9.52.
Se si utilizza l'esempio mostrato di seguito (basato sull'esempio del cavallo da corsa), al primo caricamento della pagina viene visualizzata una finestra di avviso. Ma se poi vai a un altro URL e quindi premi il pulsante Indietro per tornare a questa pagina, non visualizzi una finestra di avviso in Opera (ma lo fai negli altri browser).

Comunque, penso che questo sia abbastanza vicino per ora. Grazie a tutti!

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Untitled Document</title>
<meta http-equiv="expires" content="0">
<script src="jquery.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready( 
                    function(){
                      alert('test');
                    }
                 );
</script>
</head>
<body>
<h1>Test of the page load event and the Back button using jQuery</h1>
</body>
</html>

1

L'evento di scaricamento non funziona correttamente su Internet Explorer 9. L'ho provato con l'evento di caricamento (onload ()), funziona correttamente su Internet Explorer 9 e FF5 .

Esempio:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript">
    jQuery(window).bind("load", function() {
        $("[name=customerName]").val('');
    });
</script>
</head>
<body>
    <h1>body.jsp</h1>
    <form action="success.jsp">
        <div id="myDiv">

        Your Full Name: <input name="yourName" id="fullName"
            value="Your Full Name" /><br> <br> <input type="submit"><br>

        </div>

    </form>
</body>
</html>

0

Ho usato un modello html. Nel file custom.js di questo modello, c'era una funzione come questa:

    jQuery(document).ready(function($) {

       $(window).on('load', function() {
          //...
       });

    });

Ma questa funzione non funzionava quando torno indietro dopo andare su un'altra pagina.

Quindi, ho provato questo e ha funzionato:

    jQuery(document).ready(function($) {
       //...
    });

   //Window Load Start
   window.addEventListener('load', function() {
       jQuery(document).ready(function($) {
          //...
       });
   });

Ora ho 2 funzioni "pronte" ma non danno alcun errore e la pagina funziona molto bene.

Tuttavia, devo dichiarare che è stato testato su Windows 10 - Opera v53 e Edge v42 ma nessun altro browser. Tieni presente questo ...

Nota: la versione jquery era 3.3.1 e la versione di migrazione era 3.0.0

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.