¿Hay un evento de carga entre navegadores al hacer clic en el botón Atrás?

185

Para todos los principales navegadores (excepto IE), el onloadevento JavaScript no se dispara cuando la página se carga como resultado de una operación de botón de retroceso, solo se dispara cuando la página se carga por primera vez.

¿Alguien puede señalarme un código de ejemplo para varios navegadores (Firefox, Opera, Safari, IE, ...) que resuelva este problema? Estoy familiarizado con el pageshowevento de Firefox, pero desafortunadamente ni Opera ni Safari implementan esto.

Cuenta
fuente
66
Esto no es un problema: permite que la página web se cargue rápidamente cuando el usuario presiona el botón Atrás. Vea mi respuesta a continuación para más detalles. Las soluciones sugeridas aquí hacen que la página web sea más molesta para el usuario, ya que la navegación hacia atrás / adelante es más lenta.
Nickolay
2
@romkyns: tu comentario no está relacionado con esta pregunta. Cuando los navegadores no restauran el estado JS / DOM, activan el evento de carga.
Nickolay
Botón de retroceso del historial de iOS 5+ resuelto aquí stackoverflow.com/a/12652160/1090395
Mladen Janjetovic

Respuestas:

117

Chicos, descubrí que JQuery solo tiene un efecto: la página se vuelve a cargar cuando se presiona el botón Atrás. Esto no tiene nada que ver con " listo ".

¿Como funciona esto? Bueno, JQuery agrega un detector de eventos de descarga .

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

Por defecto, no hace nada. Pero de alguna manera esto parece desencadenar una recarga en Safari, Opera y Mozilla, sin importar lo que contenga el controlador de eventos.

[ editar (Nickolay) : he aquí por qué funciona de esa manera: webkit.org , developer.mozilla.org . Lea esos artículos (o mi resumen en una respuesta separada a continuación) y considere si realmente necesita hacer esto y hacer que su página se cargue más lentamente para sus usuarios.]

No lo puedo creer? Prueba esto:

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

Verá resultados similares cuando use JQuery.

Es posible que desee comparar a este sin descargar

<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>
usuario123444555621
fuente
1
Muy agradable ... aunque esta es una característica / error no documentado, y podría dejar de funcionar en futuras versiones del navegador, pero sigue siendo interesante.
Wadih M.
3
Esto también funciona (no olvide la parte onunload = "", de lo contrario no funcionará en ff3): <body onload = "alert ('onload');" onunload = "">
Wadih M.
3
Esto se debe a que el navegador supone que la página no se puede almacenar en caché si tiene un onunloadcontrolador (la página ya ha destruido todo; ¿por qué almacenarla en caché?).
Casey Chu
14
Parece que la respuesta no funciona en los navegadores modernos, verificada en la última versión de Chrome y Opera
Andrew
10
no funciona en el safari de iPad ... por favor, desmarque esto como respuesta
xus
74

Algunos navegadores modernos (Firefox, Safari y Opera, pero no Chrome) admiten el caché especial "atrás / adelante" (lo llamaré bfcache, que es un término inventado por Mozilla), involucrado cuando el usuario navega hacia atrás. A diferencia del caché regular (HTTP), captura el estado completo de la página (incluido el estado de JS, DOM). Esto le permite volver a cargar la página más rápido y exactamente como lo dejó el usuario.

Se loadsupone que el evento no se activa cuando la página se carga desde este bfcache. Por ejemplo, si creó su IU en el controlador "cargar", y el evento "cargar" se activó una vez en la carga inicial, y la segunda vez cuando la página se volvió a cargar desde el bfcache, la página terminaría con elementos de IU duplicados.

Esta es también la razón por la cual agregar el controlador "descargar" evita que la página se almacene en el bfcache (lo que hace que sea más lento para volver a navegar): el controlador de descarga podría realizar tareas de limpieza, lo que podría dejar la página en estado inviable.

Para las páginas que necesitan saber cuándo se navega lejos / atrás, Firefox 1.5+ y la versión de Safari con la corrección del error 28758 admiten eventos especiales llamados "pagehow" y "pagehide".

Referencias

Nickolay
fuente
Eso es genial. Actualmente estoy en una situación en la que mis manipulaciones dom no parecen guardarse en el bfcache. ¿Hay alguna situación en la que puedas esperar eso?
Benson
1
@Benson: las posibles razones por las que Firefox no guardará su página en bfcache se enumeran en la página dev.mo a la que hice enlace. No creo que sea posible guardar la página en bfcache, pero cierto estado DOM no se guardará.
Nickolay
Nickolay, entiendo tu renuencia a forzar una recarga y deshacer el buen trabajo realizado por el bfcache, pero ¿hay alguna otra forma de actualizar el dom de la página en el bfcache? Por ejemplo, considere la situación en la que paso de una página que tiene una lista de mensajes a uno de ellos, y cuando retrocedo, quiero que cambie el indicador de lectura / no leído. ¿Cómo se puede hacer esto sin volver a cargar la página?
Greg
@ Greg: ¿quieres decir como desarrollador que controla la página? Dispare una solicitud ajax de un oyente de 'pagehow'.
Nickolay
¿Alguna idea sobre cómo usar jQuery Y obtener soporte rápido de bfcache?
Alex Black el
31

Me encontré con un problema que mi js no se estaba ejecutando cuando el usuario había hecho clic hacia atrás o hacia adelante. Primero me propuse detener el almacenamiento en caché del navegador, pero este no parecía ser el problema. Mi javascript se configuró para ejecutarse después de cargar todas las bibliotecas, etc. Lo comprobé con el evento readyStateChange.

Después de algunas pruebas, descubrí que readyState de un elemento en una página en la que se ha hecho clic en la parte posterior no se 'carga' sino 'se completa'. Agregar || element.readyState == 'complete'a mi declaración condicional resolvió mis problemas.

Solo pensé en compartir mis hallazgos, espero que ayuden a alguien más.

Editar para completar

Mi código tenía el siguiente aspecto:

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

En el ejemplo de código anterior, la variable de secuencia de comandos era un elemento de secuencia de comandos recién creado que se había agregado al DOM.

Brian Heese
fuente
77
¿Dónde agregaste esto? ¿Y cómo conseguiste disparar algo después de que el usuario respondiera? ¡Por favor muéstranos un código!
Keerigan
¿Qué quieres decir cuando dices "mi declaración condicional"?
Phillip Senn
1
@Phillip Una declaración condicional es una declaración if.
Brian Heese el
22

OK, aquí hay una solución final basada en la solución inicial de ckramer y el ejemplo de palehorse que funciona en todos los navegadores, incluido Opera. Si configura history.navigationMode como 'compatible', la función ready de jQuery se activará en las operaciones del botón Atrás en Opera, así como en los otros navegadores principales.

Esta página tiene más información .

Ejemplo:

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

Probé esto en Opera 9.5, IE7, FF3 y Safari y funciona en todos ellos.

Cuenta
fuente
2
Obviamente ha pasado un tiempo (unos 5,5 años), pero vale la pena señalar que su enlace está muerto.
Jeff
2
Esta solución no me funciona. Tengo este problema en la última versión de Firefox (45.0.1)
Armin el
6

No pude hacer que los ejemplos anteriores funcionen. Simplemente quería activar una actualización de ciertas áreas div modificadas al volver a la página mediante el botón Atrás. El truco que utilicé fue establecer un campo de entrada oculto (llamado "bit sucio") a 1 tan pronto como las áreas div cambiaran del original. El campo de entrada oculto en realidad retiene su valor cuando hago clic de nuevo, así que al cargar puedo verificar este bit. Si está configurado, actualizo la página (o simplemente actualizo los divs). Sin embargo, en la carga original, el bit no está configurado, por lo que no pierdo el tiempo cargando la página dos veces.

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

Y se activaría correctamente cada vez que haga clic en el botón Atrás.

thorie
fuente
3
Si bien esto no funciona en Firefox, creo que es una forma astuta de manejar la situación en IE / Chrome, donde la persistencia del campo oculto es muy útil. He usado tu truco y también el evento "pagehow", así que cubro todos los navegadores principales.
Magnus Smith el
¿Qué navegador no funciona con las páginas? ¿Cómo funciona?
Justin
4

Si recuerdo bien, agregar un evento unload () significa que la página no se puede almacenar en caché (en caché hacia adelante / hacia atrás), porque su estado cambia / puede cambiar cuando el usuario se aleja. Por lo tanto, no es seguro restaurar el estado de último segundo de la página al volver a ella navegando a través del objeto de historial.


fuente
4

Pensé que esto sería para "descargar", no para cargar la página, ya que no estamos hablando de disparar un evento al presionar "Volver". $ document.ready () es para eventos deseados en la carga de la página, sin importar cómo llegue a esa página (es decir, redirigir, abrir el navegador a la URL directamente, etc.), no al hacer clic en "Atrás", a menos que esté hablando sobre qué disparar en la página anterior cuando se vuelve a cargar. Y no estoy seguro de que la página no se almacene en caché, ya que descubrí que los Javascripts todavía lo están, incluso cuando $ document.ready () está incluido en ellos. Hemos tenido que presionar Ctrl + F5 al editar nuestros scripts que tienen este evento cada vez que los revisamos y queremos probar los resultados en nuestras páginas.

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

es lo que desea para un evento de descarga al presionar "Atrás" y descargar la página actual, y también se activaría cuando un usuario cierre la ventana del navegador. Esto sonaba más como lo que deseaba, incluso si me superan en número con las respuestas $ document.ready (). Básicamente, la diferencia es entre un evento que se activa en la página actual mientras se cierra o en el que se carga al hacer clic en "Atrás" mientras se carga. Probado en IE 7 bien, no puedo hablar por los otros navegadores ya que no están permitidos donde estamos. Pero esta podría ser otra opción.

Tom
fuente
4

Puedo confirmar a ckramer que el evento listo de jQuery funciona en IE y Firefox. Aquí hay una muestra:

<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>
caballo pálido
fuente
4

para las personas que no quieren usar toda la biblioteca jquery, extraje la implementación en un código separado. Tiene solo 0,4 KB de tamaño.

Puede encontrar el código, junto con un tutorial en alemán en este wiki: http://www.easy-coding.de/wiki/html-ajax-und-co/onload-event-cross-browser-kompatibler-domcontentloaded.html

Torben Brodt
fuente
1
El enlace solitario se considera una respuesta pobre (ver preguntas frecuentes ) ya que no tiene sentido por sí mismo y no se garantiza que el recurso objetivo esté vivo en el futuro . Sería preferible incluir aquí las partes esenciales de la respuesta y proporcionar el enlace para referencia.
j0k
3

El evento listo de jQuery fue creado solo para este tipo de problema. Es posible que desee profundizar en la implementación para ver qué sucede debajo de las cubiertas.

ckramer
fuente
66
Mucho tiempo después, readyno parece activarse en Firefox cuando se usa el botón Atrás. Ver también la respuesta de Nickolay .
Arjan
2

Bill, me atrevo a responder tu pregunta, sin embargo, no estoy 100% seguro con mis conjeturas. Creo que, aparte de los navegadores IE, cuando se lleva al usuario a una página en el historial, no solo cargará la página y sus recursos de la memoria caché, sino que también restaurará todo el estado DOM (sesión de lectura). IE no realiza la restauración DOM (o al menos no lo hizo) y, por lo tanto, el evento de carga parece ser necesario para la reinicialización adecuada de la página allí.

Sergey Ilinsky
fuente
2

Probé la solución de Bill usando $ (document) .ready ... pero al principio no funcionó. Descubrí que si el script se coloca después de la sección html, no funcionará. Si es la sección principal, funcionará pero solo en IE. El script no funciona en Firefox.

Johann
fuente
1

Bien, probé esto y funciona en Firefox 3, Safari 3.1.1 e IE7, pero no en Opera 9.52.
Si utiliza el ejemplo que se muestra a continuación (basado en el ejemplo de palehorse), aparece una ventana emergente de cuadro de alerta cuando se carga la página por primera vez. Pero si luego va a otra URL y luego presiona el botón Atrás para volver a esta página, no aparece un cuadro de alerta emergente en Opera (pero sí en los otros navegadores).

De todos modos, creo que esto está lo suficientemente cerca por ahora. ¡Gracias a todos!

<!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>
Cuenta
fuente
1

El evento de descarga no funciona bien en IE 9. Lo probé con el evento de carga (onload ()), funciona bien en IE 9 y FF5 .

Ejemplo:

<%@ 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>
mallesham
fuente
0

He usado una plantilla html. En el archivo custom.js de esta plantilla, había una función como esta:

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

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

    });

Pero esta función no estaba funcionando cuando vuelvo atrás después de ir a otra página.

Entonces, probé esto y funcionó:

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

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

Ahora, tengo 2 funciones "listas" pero no da ningún error y la página funciona muy bien.

Sin embargo, tengo que declarar que ha probado en Windows 10 - Opera v53 y Edge v42 pero no en otros navegadores. Ten en cuenta esto ...

Nota: la versión de jquery fue 3.3.1 y la versión de migración fue 3.0.0

bafsar
fuente