Pregunta ¿Cómo puedo detectar si un usuario ha llegado a una página usando el botón Atrás?


Esta pregunta es similar a Seguir cuando el usuario pulsa el botón Atrás en el navegador, pero no es lo mismo ... Tengo una solución y la estoy publicando aquí para referencia y comentarios. Si alguien tiene mejores opciones, ¡soy todo oídos!

La situación es que tengo una página con una "edición in situ", a la flickr. Es decir. hay una DIV "haga clic aquí para agregar una descripción" que, al hacer clic, se convierte en TEXTAREA con los botones Guardar y Cancelar. Al hacer clic en Guardar, se publican los datos en el servidor para actualizar la base de datos y se coloca la nueva descripción en el DIV en lugar de TEXTAREA. Si la página se actualiza, la nueva descripción se muestra desde la base de datos con la opción "hacer clic para editar". Cosas bastante estándar de la web 2.0 en estos días.

El problema es que si:

  1. la página se carga sin la descripción
  2. una descripción es agregada por el usuario
  3. la página se navega hacia afuera haciendo clic en un enlace
  4. el usuario hace clic en el botón Atrás

Entonces, lo que se muestra (desde el caché del navegador) es la versión de la página sin el DIV modificado dinámicamente que contiene la nueva descripción.

Este es un problema bastante grande ya que el usuario asume que su actualización se ha perdido y no necesariamente entenderá que necesita actualizar la página para ver los cambios.

Entonces, la pregunta es: ¿cómo se puede marcar una página como modificada después de que se ha cargado, y luego detectar cuándo el usuario "regresa a ella" y forzar una actualización en esa situación?


76
2018-05-06 10:48


origen


Respuestas:


Use una forma oculta Los datos del formulario se conservan (típicamente) en los navegadores cuando recarga o presiona el botón Atrás para regresar a una página. Lo siguiente va en su página (probablemente cerca de la parte inferior):

<form name="ignore_me">
    <input type="hidden" id="page_is_dirty" name="page_is_dirty" value="0" />
</form>

En su javascript, necesitará lo siguiente:

var dirty_bit = document.getElementById('page_is_dirty');
if (dirty_bit.value == '1') window.location.reload();
function mark_page_dirty() {
    dirty_bit.value = '1';
}

El js que olfatea el formulario tiene que ejecutarse después de que el html se haya analizado por completo, pero puede poner tanto el formulario como el js en línea en la parte superior de la página (js segundos) si la latencia del usuario es una preocupación grave.


73
2018-04-12 22:58



Aquí hay una solución moderna muy fácil para este viejo problema.

if (window.performance && window.performance.navigation.type == window.performance.navigation.TYPE_BACK_FORWARD) {
    alert('Got here using the browser "Back" or "Forward" button.');
}

window.performance es actualmente compatible con todos los principales navegadores.


27
2017-08-24 09:31



Este artículo lo explica. Vea el código a continuación: http://www.webkit.org/blog/516/webkit-page-cache-ii-the-unload-event/

<html>
    <head>
        <script>

            function pageShown(evt){
                if (evt.persisted) {
                    alert("pageshow event handler called.  The page was just restored from the Page Cache (eg. From the Back button.");
                } else {
                    alert("pageshow event handler called for the initial load.  This is the same as the load event.");
                }
            }

            function pageHidden(evt){
                if (evt.persisted) {
                    alert("pagehide event handler called.  The page was suspended and placed into the Page Cache.");
                } else {
                    alert("pagehide event handler called for page destruction.  This is the same as the unload event.");
                }
            }

            window.addEventListener("pageshow", pageShown, false);
            window.addEventListener("pagehide", pageHidden, false);

        </script>
    </head>
    <body>
        <a href="http://www.webkit.org/">Click for WebKit</a>
    </body>
</html>

11
2018-06-15 22:05



Como mencioné anteriormente, encontré una solución y la estoy publicando aquí para referencia y comentarios.

La primera etapa de la solución es agregar lo siguiente a la página:

<!-- at the top of the content page -->
<IFRAME id="page_is_fresh" src="fresh.html" style="display:none;"></IFRAME>
<SCRIPT style="text/javascript">
  function reload_stale_page() { location.reload(); }
</SCRIPT>

Los contenidos de fresh.html no son importantes, entonces lo siguiente debería ser suficiente:

<!-- fresh.html -->
<HTML><BODY></BODY></HTML>

Cuando el código del lado del cliente actualiza la página, necesita marcar la modificación de la siguiente manera:

function trigger_reload_if_user_clicks_back_button()
{
  // "dis-arm" the reload stale page function so it doesn't fire  
  // until the page is reloaded from the browser's cache
  window.reload_stale_page = function(){};

  // change the IFRAME to point to a page that will reload the 
  // page when it loads
  document.getElementById("page_is_fresh").src = "stale.html";
}

stale.html hace todo el trabajo: cuando está cargado llamará al reload_stale_page función que actualizará la página si es necesario. La primera vez que se carga (es decir, después de realizar la modificación, reload_stale_page la función no hará nada).

<!-- stale.html -->
<HTML><BODY>
<SCRIPT type="text/javascript">window.parent.reload_stale_page();</SCRIPT>
</BODY></HTML>

A partir de mi (mínimo) examen en esta etapa, esto parece funcionar como se desea. ¿He pasado por alto algo?


2
2018-05-06 11:07



Puede usar localStorage o sessionStorage (http://www.w3schools.com/html/html5_webstorage.asp) para establecer una bandera (en lugar de usar una forma oculta).


2
2018-06-02 14:29



Aquí hay una versión de jQuery. Me he encontrado con la necesidad de usarlo algunas veces debido a la forma en que Safari desktop / mobile maneja la caché cuando un usuario presiona el botón Atrás.

$(window).bind("pageshow", function(event) {
    if (event.originalEvent.persisted) {
        // Loading from cache
    }
});

2
2018-03-31 14:20



Puedes resolverlo usando el antes de descargar evento:

window.onbeforeunload = function () { }

Tener un antes de descargar la función de gestor de eventos vacío significa que la página se reconstruirá cada vez que se acceda a ella. Los javascripts volverán a ejecutarse, los scripts del lado del servidor se volverán a ejecutar, la página se compilará como si el usuario estuviera tocando por primera vez, incluso si el usuario llega a la página simplemente presionando el botón Atrás o Atrás .

Aquí está el código completo de un ejemplo:

<html>
<head>
<title>onbeforeunload.html</title>
<script>
window.onbeforeunload = function () { }

function myfun()
{
   alert("The page has been refreshed.");
}
</script>

<body onload="myfun()">

Hello World!<br>

</body>
</html>

Pruébelo, navegue fuera de esta página y luego regrese usando los botones "Atrás" o "Adelante" en su navegador.

Funciona bien en IE, FF y Chrome.

Por supuesto, puedes hacer lo que quieras dentro mi diversion función.

Más información: http://www.hunlock.com/blogs/Mastering_The_Back_Button_With_Javascript


1
2018-06-04 04:05



Usando esta página, especialmente incorporando el comentario de @sajith sobre la respuesta de @Nick White y esta página: http://www.mrc-productivity.com/techblog/?p=1235 

<form name="ignore_me" style="display:none">
    <input type="text" id="reloadValue" name="reloadValue" value="" />
</form>

$(function ()
{
    var date = new Date();
    var time = date.getTime();

    if ($("#reloadValue").val().length === 0)
    {
        $("#reloadValue").val(time);
    }
    else
    {
        $("#reloadValue").val("");
        window.location.reload();
    }
});

1
2018-02-26 04:20



Me encontré con un problema similar hoy y lo resolví con localStorage (aquí con un poco de jQuery):

$(function() {

    if ($('#page1').length) {
        // this code must only run on page 1

        var checkSteps = function () {
            if (localStorage.getItem('steps') == 'step2') {
                // if we are here, we know that:
                // 1. the user is on page 1
                // 2. he has been on page 2
                // 3. this function is running, which means the user has submitted the form
                // 4. but steps == step2, which is impossible if the user has *just* submitted the form
                // therefore we know that he has come back, probably using the back button of his browser
                alert('oh hey, welcome back!');
            } else {
                setTimeout(checkSteps, 100);
            }
        };

        $('#form').on('submit', function (e) {
            e.preventDefault();
            localStorage.setItem('steps', 'step1'); // if "step1", then we know the user has submitted the form
            checkOrderSteps();
            // ... then do what you need to submit the form and load page 2
        });
    }

    if ($('#page2').length) {
        // this code must only run on page 2
        localStorage.setItem('steps', 'step2');
    }

});

Si básicamente:

En la página 1, cuando el usuario envía el formulario, establecemos un valor "steps" en localStorage para indicar qué paso ha realizado el usuario. Al mismo tiempo, lanzamos una función con tiempo de espera que verificará si este valor ha sido cambiado (por ejemplo, 10 veces / segundo).

En la página 2, cambiamos inmediatamente dicho valor.

Entonces, si el usuario usa el botón Atrás y el navegador restaura la página 1 en el estado exacto en que se encontraba cuando lo dejamos, la función checkSteps aún se está ejecutando, y es capaz de detectar que el valor en localStorage ha cambiado (y puede tomar las medidas apropiadas ) Una vez que este control ha cumplido su propósito, no hay necesidad de continuar ejecutándolo, por lo que simplemente no usamos setTimeout nunca más.


0
2018-06-08 15:29