Pregunta

En una aplicación web en la que estoy trabajando, estoy capturando onBeforeUnload para preguntar al usuario si realmente quiere salir.

Ahora, si decide quedarse, hay varias cosas que me gustaría hacer. Lo que estoy tratando de averiguar es que él realmente eligió quedarse.

Por supuesto, puedo declarar un SetTimeout para " x " segundos, y si eso se dispara, entonces significaría que el usuario todavía está allí (porque no nos descargaron). El problema es que el usuario puede tomar cualquier momento para decidir si quedarse o no ...

Primero esperaba que mientras se mostraba el diálogo, las llamadas a SetTimeout no se dispararan, así que podría establecer un tiempo de espera por un corto tiempo y solo se dispararía si el usuario decidía quedarse. Sin embargo, los tiempos de espera se activan mientras se muestra el cuadro de diálogo, por lo que no funciona.

Otra idea que probé es capturar movimientos del mouse en la ventana / documento. Mientras se muestra el cuadro de diálogo, mouseMoves no se dispara, a excepción de una extraña excepción que realmente se aplica a mi caso, por lo que tampoco funcionará.

¿Alguien puede pensar en otra forma de hacer esto?

¡Gracias!


(En caso de que tenga curiosidad, la razón por la que el mouseMove de captura no funciona es que tengo un IFrame en mi página, que contiene un sitio de otro dominio. Si al momento de descargar la página, el foco está dentro del IFrame, mientras se muestra el cuadro de diálogo, aparece el evento MouseMove una vez que el mouse se mueve desde dentro del IFrame hacia el exterior (al menos en Firefox). Probablemente sea un error, pero aún así, es muy probable que suceda en nuestro caso, por lo que no puedo usar este método).

¿Fue útil?

Solución

Lo que terminé haciendo fue conectarme al evento de clic de mi documento, y una vez que recibí un clic consideré que el usuario se había quedado.

No es una buena solución, en la mayoría de los casos (si eres un DiggBar) tendrás muchos falsos negativos (la gente se habrá quedado y nunca lo sabrás), pero en nuestro caso tuvo sentido. porque las personas interactúan en gran medida con nuestro sitio, no solo con los sitios enmarcados.

Esencialmente, mi código hace esto ...

function OnBeforeUnload() {
    Event.observe(document, "click", UserStayed);
    if (IConsiderTheIFrameMightBeTryingToPopOut) {
        return "The site is trying to escape. Do you want to stay?";
    }
}

function UserStayed() {
Event.stopObserving(document, "click", UserStayed);
    // New we know the user is still with us for sure.
}

Otros consejos

He estado investigando esta pregunta en línea durante los últimos días y la respuesta, invariablemente, es " no " no se puede decir, con seguridad, que un usuario se quedó o se fue (aparte del hecho de que su aplicación deja de funcionar si el usuario se va). Odio " no " respuestas Se me ocurrió la siguiente utilidad.

var OnBeforeUnload = (function(){
    var
    FDUM = new Function,
    AFFIRM = function(){ return true; };

    var _reg = function(msg,opts){
        opts = opts || {};
        var
            pid = null,
            pre = typeof opts.prefire == 'function' ? opts.prefire : FDUM,
            callback = typeof opts.callback == 'function' ? opts.callback : FDUM,
            condition = typeof opts.condition == 'function' ? opts.condition : AFFIRM;

        window.onbeforeunload = function(){
            return condition() ? (pre(),setTimeout(function(){ pid = setTimeout(callback,20); },1),msg) : void 0; 
        }

        window.onunload = function(){ clearTimeout(pid); };

    }

    var _unreg = function(){ window.onbeforeunload = null;  }

    return {
        register : _reg,
        unregister : _unreg
    };

})();

Por lo tanto, una llamada como

OnBeforeUnload.register('Hello!',{ 
    condition:function_that_returns_true_to_fire_event_false_to_ignore,
    prefire:function_to_call_on_page_exit_attempt, 
    callback:function_to_call_if_user_stays
});
Se llamará a la condición

dentro del controlador para ver si debe activarse o no. Si es así, prefire se ejecuta antes de que se muestre la ventana emergente al usuario (es posible que desee pausar un video) y la devolución de llamada se producirá SOLAMENTE si el usuario se queda.

Mi lógica era iniciar un setTimeout en el cuerpo del controlador de eventos. El setTimeout no se ejecutará hasta que el usuario presione uno de los botones. Después de que lo hacen, se dispara de inmediato. El setTimeout en este caso no llama a la devolución de llamada, sino a una función proxy que ejecuta otro tiempo de espera para la devolución de llamada con un retraso de 20 ms. Si el usuario permanece en la página, se ejecuta la devolución de llamada. Si no, se adjunta otro controlador a onunload que borra el tiempo de espera para llamar a la devolución de llamada, asegurando que la devolución de llamada nunca se llame. Solo tuve la oportunidad de comprobarlo en Firefox, IE y Chrome, pero hasta ahora ha funcionado en los tres sin ningún problema.

Espero que esto ayude a las personas tan frustradas como lo estaba por la patente " no " Dado universalmente a esta pregunta. Es posible que este código no sea perfecto, pero creo que va por el camino correcto.

Este es el mayor éxito para este tipo de pregunta, y sé que el caso específico (de hace 8 años) no pudo usar esta solución porque estaba en un iFrame, pero cualquier futura persona probablemente reciba más ayuda. por la siguiente respuesta que las anteriores:

Puedes saber fácilmente si se han quedado con un oyente de eventos corporales, creo que mousemove y keydown combinados deberían ser suficientes.

Para saber si se fueron, necesitarás algo del servidor.

En general, se verá algo así (tendrás que completar tú mismo las llamadas ajax al servidor):

window.addEventListener("beforeunload", function(event){
    //tell your server they are attempting to leave
    var tryLeaveID = serverLogAttempToLeave();

    //an element with giant letters and warning text, because you can no longer set text on the alert box
    var unsavedWarning = document.getElementById("unsavedChangesWarning");
    unsavedWarning.style.display = "block";

    var onStay = function() {
        //if they stay, tell your server so
        serverRevokeAttemptToLeave(tryLeaveID);
        unsavedWarning.style.display = "none";
        document.body.removeEventListener("mousemove", onStay);
        document.body.removeEventListener("keydown", onStay);
    }

    document.body.addEventListener("mousemove", onStay);
    document.body.addEventListener("keydown", onStay);


    var dialogText =  "undisplayed text";
    event.returnValue = dialogText;
    return dialogText;
});

En el lado del servidor, vas a tener que usar algo feo, un temporizador. Haga una pila de intentos para irse y elimínelos ya sea según lo solicitado en la estadía, o después de un minuto o más, como una licencia confirmada. No puedo imaginar ningún caso en el que saber si el usuario se fue tiene más tiempo que unos pocos minutos, pero si tiene uno, coméntelo porque me gustaría pensarlo.

¿Por qué no solo usa el método que usa StackOverflow, donde obtiene un cuadro emergente que le permite elegir?

  

¿Seguro que quieres salir de esta página?

     

Has comenzado a escribir o editar una publicación.

     

Presione Aceptar para continuar o Cancelar para permanecer en la página actual

Entonces no importa cuánto tiempo tomen. Si hacen clic en un botón, se van. Si hacen clic en el otro, se quedan.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top