¿Cómo capturar el evento de cierre de la ventana del navegador?

149

Quiero capturar el evento de cierre de ventana / pestaña del navegador. He intentado lo siguiente con jQuery:

jQuery(window).bind(
    "beforeunload", 
    function() { 
        return confirm("Do you really want to close?") 
    }
)

Pero también funciona en el envío de formularios, que no es lo que quiero. Quiero un evento que se active solo cuando el usuario cierre la ventana.

khelll
fuente

Respuestas:

212

El beforeunloadevento se activa cada vez que el usuario abandona su página por cualquier motivo.

Por ejemplo, se activará si el usuario envía un formulario, hace clic en un enlace, cierra la ventana (o pestaña) o va a una nueva página utilizando la barra de direcciones, el cuadro de búsqueda o un marcador.

Puede excluir envíos de formularios e hipervínculos (excepto de otros marcos) con el siguiente código:

var inFormOrLink;
$('a').on('click', function() { inFormOrLink = true; });
$('form').on('submit', function() { inFormOrLink = true; });

$(window).on("beforeunload", function() { 
    return inFormOrLink ? "Do you really want to close?" : null; 
})

Para las versiones jQuery anteriores a 1.7, intente esto:

var inFormOrLink;
$('a').live('click', function() { inFormOrLink = true; });
$('form').bind('submit', function() { inFormOrLink = true; });

$(window).bind("beforeunload", function() { 
    return inFormOrLink ? "Do you really want to close?" : null; 
})

El livemétodo no funciona con el submitevento, por lo que si agrega un nuevo formulario, también deberá vincularlo con el controlador.

Tenga en cuenta que si un controlador de eventos diferente cancela el envío o la navegación, perderá el mensaje de confirmación si la ventana se cierra más tarde. Se podría arreglar eso registrando el tiempo de los submity clickeventos, y comprobando si la beforeunloadpasa más de un par de segundos más tarde.

SLaks
fuente
8
sí, trabajando genial! Las versiones más nuevas de jquery admiten $ ('formulario'). Live ('submit, function () {}).
Venkat D.
44
Su solución es buena, pero ¿cómo cancelo el evento en caso de actualización? Quiero el evento solo si el navegador está cerrado, no hay caso de actualización
Refael
Parece que el navegador muestra el valor de retorno de beforeunload como un diálogo de confirmación. Así que creo que esta respuesta es más precisa: enlace
tahagh
2
Hace esto de actualización mango de una página utilizando Ctrl + r, F5, Ctrl + Shift + ry el cambio de la dirección URL del navegador?
Arti
1
@ Jonny: Ahora es justo .on().
SLaks
45

Tal vez solo desvincula el beforeunloadcontrolador de eventos dentro del controlador de eventos del formulario submit:

jQuery('form').submit(function() {
    jQuery(window).unbind("beforeunload");
    ...
});
karim79
fuente
3
¿No es tan fácil no usar jQuery especificando esto en la definición de etiqueta de formulario? : `<form onsubmit =" window.onbeforeunload = null; ">
temor el
44
@awe Pero necesitarías incluir eso onsubmit=...en cada formulario. (Tengo muchas formas por página, en cierta aplicación web)
KajMagnus
16

Para una solución de navegador cruzado (probado en Chrome 21, IE9, FF15), considere usar el siguiente código, que es una versión ligeramente modificada del código de Slaks:

var inFormOrLink;
$('a').live('click', function() { inFormOrLink = true; });
$('form').bind('submit', function() { inFormOrLink = true; });

$(window).bind('beforeunload', function(eventObject) {
    var returnValue = undefined;
    if (! inFormOrLink) {
        returnValue = "Do you really want to close?";
    }
    eventObject.returnValue = returnValue;
    return returnValue;
}); 

Tenga en cuenta que desde Firefox 4, el mensaje "¿Realmente desea cerrar?" no se muestra FF solo muestra un mensaje genérico. Ver nota en https://developer.mozilla.org/en-US/docs/DOM/window.onbeforeunload

desm
fuente
3
Este funciona de manera consistente en todos los navegadores. Solo una nota rapida; He actualizado tanto los livey las binddeclaraciones a on, que funciona muy bien con el último nivel de jQuery. ¡Gracias!
Sablefoste
16
window.onbeforeunload = function () {
    return "Do you really want to close?";
};
Behnam Mohammadi
fuente
4

Para una solución que funcionó bien con controles de terceros como Telerik (ej .: RadComboBox) y DevExpress que usan las etiquetas Anchor por varias razones, considere usar el siguiente código, que es una versión ligeramente modificada del código de desm con un mejor selector para sí mismo etiquetas de anclaje de orientación:

var inFormOrLink;
$('a[href]:not([target]), a[href][target=_self]').live('click', function() { inFormOrLink = true; });
$('form').bind('submit', function() { inFormOrLink = true; });

$(window).bind('beforeunload', function(eventObject) {
    var returnValue = undefined;
    if (! inFormOrLink) {
        returnValue = "Do you really want to close?";
    }
    eventObject.returnValue = returnValue;
    return returnValue;
});
PLT
fuente
1
Esta respuesta es correcta, pero para aquellos que han tenido problemas con este evento cuando actualiza el navegador, cambie su if al siguiente código: if (inFormOrLink! == undefined &&! InFormOrLink)
LeonPierre
4

Mi respuesta está dirigida a proporcionar puntos de referencia simples.

CÓMO

Ver la respuesta de @SLaks .

$(window).on("beforeunload", function() { 
    return inFormOrLink ? "Do you really want to close?" : null; 
})

¿Cuánto tiempo tarda el navegador en cerrar finalmente su página?

Cada vez que un usuario cierra la página ( xbotón o CTRL+ W), el navegador ejecuta el beforeunloadcódigo dado , pero no indefinidamente. La única excepción es el cuadro de confirmación ( return 'Do you really want to close?) que esperará hasta la respuesta del usuario.

Cromo : 2 segundos.
Firefox : ∞ (o doble clic, o forzar al cerrar)
Borde : ∞ (o doble clic)
Explorer 11 : 0 segundos.
Safari : TODO

Lo que solíamos probar esto:

  • Un servidor Node.js Express con registro de solicitudes
  • El siguiente archivo HTML corto

Lo que hace es enviar tantas solicitudes como sea posible antes de que el navegador cierre su página (sincrónicamente).

<html>
<body>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
    <script>
    function request() {
        return $.ajax({
            type: "GET",
            url: "http://localhost:3030/" + Date.now(),
            async: true
        }).responseText;
    }
    window.onbeforeunload = () => {
        while (true) {
            request();
        }
        return null;
    }
    </script>
</body>
</html>

Salida de cromo:

GET /1480451321041 404 0.389 ms - 32  
GET /1480451321052 404 0.219 ms - 32  
...  
GET /hello/1480451322998 404 0.328 ms - 32

1957ms  2 seconds // we assume it's 2 seconds since requests can take few milliseconds to be sent.
zurfyx
fuente
3

Utilicé la respuesta Slaks, pero eso no funcionaba como está, ya que onbeforeunload returnValue se analiza como una cadena y luego se muestra en el cuadro de confirmaciones del navegador. Entonces se mostró el valor verdadero, como "verdadero".

Solo usando return funcionó. Aqui esta mi codigo

var preventUnloadPrompt;
var messageBeforeUnload = "my message here - Are you sure you want to leave this page?";
//var redirectAfterPrompt = "http://www.google.co.in";
$('a').live('click', function() { preventUnloadPrompt = true; });
$('form').live('submit', function() { preventUnloadPrompt = true; });
$(window).bind("beforeunload", function(e) { 
    var rval;
    if(preventUnloadPrompt) {
        return;
    } else {
        //location.replace(redirectAfterPrompt);
        return messageBeforeUnload;
    }
    return rval;
})
kapad
fuente
1

Tal vez podría manejar OnSubmit y establecer una marca que luego verificará en su controlador OnBeforeUnload.

i_am_jorf
fuente
1
jQuery(window).bind(
                    "beforeunload",
                      function (e) {
                          var activeElementTagName = e.target.activeElement.tagName;
                          if (activeElementTagName != "A" && activeElementTagName != "INPUT") {
                              return "Do you really want to close?";
                          }
                      })
Coding man
fuente
1

Desafortunadamente, si se trata de una recarga, una nueva redirección de página o un cierre del navegador, se activará el evento. Una alternativa es capturar la identificación que activa el evento y, si es un formulario, no active ninguna función y si no es la identificación del formulario, haga lo que quiera hacer cuando se cierre la página. No estoy seguro de si eso también es posible directamente y es tedioso.

Puede hacer algunas cosas pequeñas antes de que el cliente cierre la pestaña. JavaScript detecta la pestaña de cierre del navegador / cierra el navegador, pero si su lista de acciones es grande y la pestaña se cierra antes de que termine, no puede hacer nada. Puedes probarlo pero con mi experiencia no dependas de ello.

window.addEventListener("beforeunload", function (e) {
  var confirmationMessage = "\o/";
  /* Do you small action code here */
  (e || window.event).returnValue = confirmationMessage; //Gecko + IE
  return confirmationMessage;                            //Webkit, Safari, Chrome
});

https://developer.mozilla.org/en-US/docs/Web/Reference/Events/beforeunload?redirectlocale=en-US&redirectslug=DOM/Mozilla_event_reference/beforeunload

Gary
fuente
0

Si su envío de formulario los lleva a otra página (como supongo que lo hace, por lo tanto, se activa beforeunload), podría intentar cambiar su envío de formulario a una llamada ajax. De esta manera, no abandonarán su página cuando envíen el formulario y puede usar su beforeunloadcódigo de enlace como lo desee.

idrumgood
fuente
0

Mi problema: el evento 'onbeforeunload' solo se activaría si hubiera un número impar de envíos (clics). Tenía una combinación de soluciones de subprocesos similares en SO para que mi solución funcionara. bueno mi código hablará.

<!--The definition of event and initializing the trigger flag--->


$(document).ready(function() {
updatefgallowPrompt(true);
window.onbeforeunload = WarnUser;   
}

function WarnUser() {
var allowPrompt = getfgallowPrompt();
    if(allowPrompt) {
    saveIndexedDataAlert();
    return null;
    } else {
        updatefgallowPrompt(true);
        event.stopPropagation
    }
}

<!--The method responsible for deciding weather the unload event is triggered from submit or not--->
function saveIndexedDataAlert() {
    var allowPrompt = getfgallowPrompt();
    var lenIndexedDocs = parseInt($('#sortable3 > li').size()) + parseInt($('#sortable3 > ul').size());

    if(allowPrompt && $.trim(lenIndexedDocs) > 0) {
        event.returnValue = "Your message";
    } else {
        event.returnValue = "   ";
        updatefgallowPrompt(true);
    }
}

<!---Function responsible to reset the trigger flag---->
$(document).click(function(event) {  
$('a').live('click', function() { updatefgallowPrompt(false); });
 });

<!--getter and setter for the flag---->
function updatefgallowPrompt (allowPrompt){ //exit msg dfds
    $('body').data('allowPrompt', allowPrompt); 
}   

function getfgallowPrompt(){        
    return $('body').data('allowPrompt');   
}
Yoosaf Abdulla
fuente
0

A partir de jQuery 1.7, el método .live () está en desuso. Use .on () para adjuntar controladores de eventos. Los usuarios de versiones anteriores de jQuery deben usar .delegate () en lugar de .live ()

$(window).bind("beforeunload", function() {
    return true || confirm("Do you really want to close?"); 
}); 

en completo o enlace

$(window).unbind();
Tom
fuente
0

Prueba esto también

window.onbeforeunload = function ()
{       
    if (pasteEditorChange) {
        var btn = confirm('Do You Want to Save the Changess?');
           if(btn === true ){
               SavetoEdit();//your function call
           }
           else{
                windowClose();//your function call
           }
    }  else { 
        windowClose();//your function call
    }
};
Bhaskara Arani
fuente
-1

Solo verifica ...

function wopen_close(){
  var w = window.open($url, '_blank', 'width=600, height=400, scrollbars=no, status=no, resizable=no, screenx=0, screeny=0');
  w.onunload = function(){
    if (window.closed) {
       alert("window closed");
    }else{ 
       alert("just refreshed");
    }
  }
}
Brunno
fuente
No funciona En el momento en que se dispara el evento de descarga (por cierto, se dispara desde el documento), window.closed === false;
Sergey P. aka azure el
-1
var validNavigation = false;
            jQuery(document).ready(function () {

                wireUpEvents();
            });

            function endSession() {
                // Browser or broswer tab is closed
                // Do sth here ...
                alert("bye");
            }

            function wireUpEvents() {
                /*
                * For a list of events that triggers onbeforeunload on IE
                * check http://msdn.microsoft.com/en-us/library/ms536907(VS.85).aspx
                */
                window.onbeforeunload = function () {
                    debugger
                    if (!validNavigation) {
                        endSession();
                    }
                }

                // Attach the event keypress to exclude the F5 refresh
                $(document).bind('keypress', function (e) {
                    debugger
                    if (e.keyCode == 116) {
                        validNavigation = true;
                    }
                });

                // Attach the event click for all links in the page
                $("a").bind("click", function () {
                    debugger
                    validNavigation = true;
                });

                // Attach the event submit for all forms in the page
                $("form").bind("submit", function () {
                    debugger
                    validNavigation = true;
                });

                // Attach the event click for all inputs in the page
                $("input[type=submit]").bind("click", function () {
                    debugger
                    validNavigation = true;
                });

            }`enter code here`
Arslan Khan
fuente
-7

Lo siguiente funcionó para mí;

 $(window).unload(function(event) {
    if(event.clientY < 0) {
        //do whatever you want when closing the window..
    }
 });
Dilhan Jayathilaka
fuente
Es una función jQuery.
maxisam
77
Esto event.clientYes negativo si hace clic en el botón de cierre del navegador o en el botón de cierre de pestaña. Sin embargo, este valor es positivo cuando vuelve a cargar la página con métodos abreviados de teclado (F5, Ctrl-R) o cierra el navegador con métodos abreviados de teclado (por ejemplo, Alt-F4). Por lo tanto, no puede confiar en la posición del evento para diferenciar el evento de cierre del navegador del evento de recarga de página.
Julien Kronegg