Detecta el navegador o el cierre de pestañas


306

¿Existe algún código JavaScript / jQuery entre navegadores para detectar si el navegador o una pestaña del navegador se está cerrando, pero no debido a que se haga clic en un enlace?


1
Vea mi respuesta a esta pregunta: stackoverflow.com/questions/3735198/…
Nivas


Use sessionStorage Property, caducará una vez que se cierre el navegador. w3schools.com/jsref/prop_win_sessionstorage.asp
csandreas1

¡Mira esta respuesta! Lo encontré extremadamente útil y cubre la mayoría de los casos. stackoverflow.com/a/26275621/7192927
SukanyaPai

Respuestas:


273

Si te entiendo correctamente, quieres saber cuándo una pestaña / ventana se cierra efectivamente. Bueno, AFAIK es la única forma Javascriptde detectar ese tipo de cosas onunloady onbeforeunloadeventos.

Desafortunadamente (¿o afortunadamente?), Esos eventos también se activan cuando abandonas un sitio a través de un linkbotón de retroceso de tu navegador. Así que esta es la mejor respuesta que puedo dar, no creo que pueda detectar de forma nativa un puro closeen Javascript. Corrígeme si me equivoco aquí.


39
Correcto. Solo puede detectar cuando la página está descargada, no cuando la ventana está cerrada. Además, onbeforeunload no es estándar, por lo que no es compatible con todos los navegadores.
Guffa

77
También quería usar la función 'al cerrar', pero noté que mis usuarios ocasionalmente actualizan la pantalla presionando F5. Dado que mis controladores 'al cerrar' se invocan en dicha actualización, esto significa que no puedo usarlo como lo necesitaba (que era una verdadera 'pestaña o ventana cerrada') ... maldición, necesitamos un nuevo modelo de evento por todo esto!
Jeach

1
Ya no funciona en Chrome / Opera ... chromestatus.com/feature/5349061406228480
Samir Seetal

2
Por supuesto, esto seguirá funcionando, simplemente eliminaron un Stringvalor de retorno personalizado de onbeforeunload. Así que ahora ya no podrás mostrar un mensaje personalizado antes de descargarlo.
jAndy

@jAndy @Guffa ¿Cómo puedo saber qué ventana se disparó unload?
Egor Dudyak

125

De la documentación de Firefox

Por alguna razón, los navegadores basados ​​en Webkit no siguen las especificaciones del cuadro de diálogo. Un ejemplo de trabajo casi cruzado estaría cerca del siguiente ejemplo.

window.addEventListener("beforeunload", function (e) {
  var confirmationMessage = "\o/";

  (e || window.event).returnValue = confirmationMessage; //Gecko + IE
  return confirmationMessage;                            //Webkit, Safari, Chrome
});

Este ejemplo para manejar todos los navegadores.


2
Esta es la única solución que funcionó para mi navegador Chrome. No probé ninguna otra.
Chase Roberts

44
sí, pruebo muchas soluciones y vengo con esto al final, combinación para las mejores respuestas, y lo pruebo en todos los navegadores.
mohamed-ibrahim

1
Este método no funciona perfectamente al cerrar pestañas mientras se usa Firefox (> = ver. 44) con solo pestañas abiertas.
Rajkishore

A partir de hoy, al usar todas las versiones más recientes de los navegadores, el aviso funciona al cerrar la pestaña, navegar o cerrar el navegador para Chrome, Firefox, Opera, IE11 y Edge y también funciona cuando tiene varias pestañas abiertas, excepto Chrome donde Chrome cierra todas las pestañas sin preguntar, al menos en mi máquina al menos.
Thierry

no dar una salida adecuada como se define en la pregunta. Esto también se activó en el evento de abandono de la página, no solo cuando se cierra el navegador o se cierra la pestaña
Sunil Acharya

48

Solución simple

window.onbeforeunload = function () {
    return "Do you really want to close?";
};

77
¿Qué clase de brujería es esta? (y) ¿funciona en todos los navegadores? funciona muy bien en Chrome
Ziv Weissman

55
se activa cuando actualiza la página. Ese es mi único problema.
Leo Leoncio

66
Esta solución ya no funciona en Firefox y Chrome
Mehdi Dehghani

Esto también se activó en el evento de abandono de la página, no solo cuando se cierra el navegador o se cierra la pestaña
Sunil Acharya

20
<body onbeforeunload="ConfirmClose()" onunload="HandleOnClose()">

var myclose = false;

function ConfirmClose()
{
    if (event.clientY < 0)
    {
        event.returnValue = 'You have closed the browser. Do you want to logout from your application?';
        setTimeout('myclose=false',10);
        myclose=true;
    }
}

function HandleOnClose()
{
    if (myclose==true) 
    {
        //the url of your logout page which invalidate session on logout 
        location.replace('/contextpath/j_spring_security_logout') ;
    }   
}

// Esto funciona en IE7, si está cerrando una pestaña o navegador con una sola pestaña


2
ya. pero para el navegador de múltiples pestañas como ie8, firefox. ¿Hay algún problema al usar esto?
cometta

Resulta que el uso de este código en IE9 hará que este mensaje aparezca cuando el usuario haga clic en los botones Atrás, Adelante o Actualizar con el mouse.
Steve Wortham

Solo un aviso de que implementamos una solución similar en 2007. Esta solución ya no funciona en IE9 hace aproximadamente una semana. Dejó de funcionar (o posiblemente nunca funcionó) en navegadores con pestañas hace mucho tiempo.
tjfo

Inyecté window.onunload = "alert('wait')"y window.onbeforeunload = "alert('wait... chrome!')"utilicé la consola en Chromium / Ubuntu, pero ninguno disparó cuando cerré la pestaña.
agua helada

window.onunload = "alert('wait')"y tal no debería funcionar realmente. "La función debe asignar un valor de cadena a la propiedad returnValue del objeto Event y devolver la misma cadena". Por favor, eche un vistazo al artículo de MDN
Dmitry Vyprichenko

8

Necesitaba desconectar automáticamente al usuario cuando se cierra el navegador o la pestaña, pero no cuando el usuario navega a otros enlaces. Tampoco quería que se mostrara un mensaje de confirmación cuando eso sucede. Después de luchar con esto por un tiempo, especialmente con IE y Edge, esto es lo que terminé haciendo (comprobé trabajando con IE 11, Edge, Chrome y Firefox) después de basar el enfoque en esta respuesta .

Primero, inicie un temporizador de cuenta regresiva en el servidor en el beforeunloadcontrolador de eventos en JS. Las llamadas ajax deben ser sincrónicas para que IE y Edge funcionen correctamente. También necesitas usarreturn; para evitar que el cuadro de diálogo de confirmación se muestre así:

    window.addEventListener("beforeunload", function (e) {        
      $.ajax({
          type: "POST",
          url: startTimerUrl,
          async: false           
      });
      return;
    });

Al iniciar el temporizador se establece la cancelLogoutbandera en falso . Si el usuario actualiza la página o navega a otro enlace interno, el cancelLogoutindicador en el servidor se establece en verdadero . Una vez que transcurre el evento del temporizador, verifica la cancelLogoutbandera para ver si el evento de cierre de sesión se ha cancelado. Si el temporizador ha sido cancelado, entonces lo detendría. Si se cerró el navegador o la pestaña, la cancelLogoutbandera permanecería falsa y el controlador de eventos cerraría la sesión del usuario.

Nota de implementación: estoy usando ASP.NET MVC 5 y estoy cancelando el cierre de sesión en un Controller.OnActionExecuted()método anulado .


Esto funcionó muy bien. ¿Hay alguna razón por la que haces "async: false"? Esto genera advertencias de que las llamadas síncronas AJAX están en desuso. ¡Gracias!
cat_in_hat

1
@FoundWaldoException, como se señaló en la respuesta, descubrí que la asíncrona debía establecerse en falso para que esto funcione en IE y Edge.
Ionian316

¿Cómo cancelar el cierre de sesión OnActionExecuted?
Kiquenet

@ Kiquenet Simplemente detenga el temporizador que se inició en su código.
Ionian316

6

Lo sentimos, no pude agregar un comentario a una de las respuestas existentes, pero en caso de que quisiera implementar un tipo de diálogo de advertencia, solo quería mencionar que cualquier función de controlador de eventos tiene un argumento - evento. En su caso, puede llamar a event.preventDefault () para no dejar la página automáticamente, luego emita su propio diálogo. Considero que esta es una opción mucho mejor que usar una alerta estándar fea e insegura (). Personalmente implementé mi propio conjunto de cuadros de diálogo basados ​​en el objeto kendoWindow (la interfaz de usuario Kendo de Telerik, que es casi completamente de código abierto, excepto kendoGrid y kendoEditor). También puede usar cuadros de diálogo desde jQuery UI. Sin embargo, tenga en cuenta que tales cosas son asíncronas, y deberá vincular un controlador al evento onclick de cada botón, pero todo esto es bastante fácil de implementar.

Sin embargo, estoy de acuerdo en que la falta del evento de cierre real es terrible: si, por ejemplo, desea restablecer el estado de su sesión en el back-end solo en el caso del cierre real, es un problema.


6

Para tareas similares, puede usar sessionStorage para almacenar datos localmente hasta que se cierre la pestaña del navegador.

El sessionStorageobjeto almacena datos para una sola sesión (los datos se eliminan cuando se cierra la pestaña del navegador). ( W3Schools )

Esta es mi lapicera .

<div id="Notice">
    <span title="remove this until browser tab is closed"><u>dismiss</u>.</span>
</div>
<script>
    $("#Notice").click(function() {
     //set sessionStorage on click
        sessionStorage.setItem("dismissNotice", "Hello");
        $("#Notice").remove();
    });
    if (sessionStorage.getItem("dismissNotice"))
    //When sessionStorage is set Do stuff...
        $("#Notice").remove();
</script>

5

No hay ningún evento, pero hay una propiedad window.closedque es compatible con todos los principales navegadores en el momento de este escrito. Por lo tanto, si realmente necesita saber, puede sondear la ventana para verificar esa propiedad.

if(myWindow.closed){do things}

Nota: Sondear cualquier cosa generalmente no es la mejor solución. El window.onbeforeunloadevento debe usarse si es posible, la única advertencia es que también se dispara si te alejas.


4
$(window).unload( function () { alert("Bye now!"); } );

99
Esto no funcionará en Firefox o Chrome. Intente beforeunloadsi desea mostrar una alerta. De esta manera:$(window).on('beforeunload', function(){ alert ('Bye now')});
AdrianoRR

55
según los documentos de jQuery "La mayoría de los navegadores ignorarán las llamadas a alert (), confirm () y prompt ()" api.jquery.com/unload
katzmopolitan el

4

Intenta usarlo:

window.onbeforeunload = function (event) {
    var message = 'Important: Please click on \'Save\' button to leave this page.';
    if (typeof event == 'undefined') {
        event = window.event;
    }
    if (event) {
        event.returnValue = message;
    }
    return message;
};

$(function () {
    $("a").not('#lnkLogOut').click(function () {
        window.onbeforeunload = null;
    });
    $(".btn").click(function () {
        window.onbeforeunload = null;
});
});

3

Encontré una forma que funciona en todos mis navegadores .

Probado en las siguientes versiones: Firefox 57, Internet Explorer 11, Edge 41, uno de los últimos Chrome (no mostrará mi versión)

Nota : onbeforeunload se dispara si abandona la página de cualquier manera posible (actualizar, cerrar el navegador, redirigir, vincular, enviar ...). Si solo desea que suceda al cerrar el navegador, simplemente vincule los controladores de eventos.

  $(document).ready(function(){         

        var validNavigation = false;

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

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

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

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

        window.onbeforeunload = function() {                
            if (!validNavigation) {     
                // ------->  code comes here
            }
        };

  });

Cómo se agregará un controlador separado para cerrar el navegador ... No creo que tengamos un evento separado para esto.
blazehub

Esto fue muy útil. Necesitaba ajustar el ancla A para disparar solo para hipervínculos reales. De lo contrario, hacer clic en las pestañas de bootstrap lo estropeó: $ ("a [href! = '']"). Not ('[href ^ = "#"]'). Bind ("click", function ()
Ken Forslund

3

Como nadie lo ha mencionado todavía (más de 8 años después): un WebSocket puede ser otra forma efectiva de detectar una pestaña cerrada. Mientras la pestaña esté abierta y apunte al host, el cliente podrá mantener una conexión WebSocket activa al host.

Advertencia: Tenga en cuenta que esta solución realmente solo es viable para un proyecto si un WebSocket no requiere ningún gasto adicional significativo de lo que ya está haciendo.

Dentro de un período de tiempo de espera razonable (p. Ej., 2 minutos), el lado del servidor puede determinar que el cliente se ha ido después de que WebSocket se haya desconectado y realizar cualquier acción que desee, como eliminar los archivos temporales cargados. (En mi caso de uso extremadamente especializado, mi objetivo era terminar un servidor de aplicaciones localhost tres segundos después de que la conexión WebSocket se caiga y toda la actividad CGI / FastCGI finalice; cualquier otra conexión de mantenimiento no me afecta).

Tuve problemas para que el controlador de eventos onunload funcionara correctamente con balizas (como lo recomienda esta respuesta ). El cierre de la pestaña no pareció activar la baliza y las pestañas abiertas la activaron de maneras que podrían causar problemas. Un WebSocket resolvió el problema con el que me encontraba más limpiamente porque la conexión se cierra aproximadamente al mismo tiempo que la pestaña se cierra y el cambio de páginas dentro de la aplicación simplemente abre una nueva conexión WebSocket dentro de la ventana de retraso.


2
eso está bien. Pero, ¿no puedes compartir ningún código o procedimiento para manejarlo? Sin eso para un novato como yo no puedo entender
P Satish Patro

En realidad, no estaba claro en mi primer comentario. No conozco web socket. Entonces, solo quería ver cómo manejarlo
P Satish Patro

1
El enlace en mi comentario anterior va a algún ejemplo de código WebSocket JS. La parte del cliente JS es la parte fácil. Ese código es para mi caso de uso muy específico, aunque necesito terminar todo el servidor de aplicaciones de manera oportuna. La forma en que escribe un servidor WebSocket depende de usted y requiere una configuración del lado del servidor para conectar todo (mucha gente prefiere un backend NodeJS con frontend Nginx). Escribir un servidor habilitado para TCP / IP es un tema complejo que no es adecuado para la discusión en los comentarios y es excesivo configurar uno solo para detectar este problema en particular.
CubicleSoft

2
//Detect Browser or Tab Close Events
$(window).on('beforeunload',function(e) {
  e = e || window.event;
  var localStorageTime = localStorage.getItem('storagetime')
  if(localStorageTime!=null && localStorageTime!=undefined){
    var currentTime = new Date().getTime(),
        timeDifference = currentTime - localStorageTime;

    if(timeDifference<25){//Browser Closed
       localStorage.removeItem('storagetime');
    }else{//Browser Tab Closed
       localStorage.setItem('storagetime',new Date().getTime());
    }

  }else{
    localStorage.setItem('storagetime',new Date().getTime());
  }
});

Enlace JSFiddle

Hola a todos, pude lograr clics en 'Detectar navegador y evento de cierre de pestaña' al usar el almacenamiento local del navegador y la marca de tiempo. Espero que todos ustedes resuelvan sus problemas utilizando esta solución.

Después de mi investigación inicial, descubrí que cuando cerramos un navegador, el navegador cerrará todas las pestañas una por una para cerrar completamente el navegador. Por lo tanto, observé que habrá muy poco tiempo de retraso entre el cierre de las pestañas. Así que tomé este retraso como mi principal punto de validación y pude lograr la detección de eventos de cierre de navegador y pestaña.

Lo probé en la versión 76.0.3809.132 del navegador Chrome y encontré que funcionaba

:) Vote si encuentra útil mi respuesta ...


Bueno, esto me dio una idea. Estoy configurando una marca de tiempo más 10 segundos en el almacenamiento local después del inicio de sesión y en el evento antes de la descarga. Al cargar, verifico si pasó el tiempo y luego redirijo a la página de inicio de sesión. Gracias :)
G4BB3R

1
window.onbeforeunload = function() {
  console.log('event');
  return false; //here also can be string, that will be shown to the user
}

2
here also can be string, that will be shown to the usersin embargo, en Firefox, sí lo hace en Chrome ...
TrySpace

Cualquier valor de retorno (cadena) se muestra solo en MSIE <= 11. Así que, básicamente, es inútil para todos los demás navegadores.
OSWorX

1

Es posible verificarlo con la ayuda de window.closed en un controlador de eventos en el evento 'descargar' como este, pero se requiere el uso del tiempo de espera (por lo que no se puede garantizar el resultado si algo demora o evita que se cierre la ventana):

Ejemplo de JSFiddle (Probado en los últimos Safari, FF, Chrome, Edge e IE11)

var win = window.open('', '', 'width=200,height=50,left=200,top=50');
win.document.write(`<html>
   <head><title>CHILD WINDOW/TAB</title></head>
   <body><h2>CHILD WINDOW/TAB</h2></body>
</html>`);
win.addEventListener('load',() => {
    document.querySelector('.status').innerHTML += '<p>Child was loaded!</p>';
});
win.addEventListener('unload',() => {
    document.querySelector('.status').innerHTML += '<p>Child was unloaded!</p>';
    setTimeout(()=>{
        document.querySelector('.status').innerHTML +=  getChildWindowStatus();
    },1000);
});
win.document.close()
document.querySelector('.check-child-window').onclick = ()=> {
    alert(getChildWindowStatus());
}
function getChildWindowStatus() {
  if (win.closed) { 
      return 'Child window has been closed!';
  } else {
      return 'Child window has not been closed!';
  }
}

1

He intentado todas las soluciones anteriores, ninguna de ellas realmente funcionó para mí, especialmente porque hay algunos componentes de Telerik en mi proyecto que tienen el botón 'Cerrar' para ventanas emergentes, y llama al evento 'beforeunload'. Además, el selector de botones no funciona correctamente cuando tiene una cuadrícula de Telerik en su página (me refiero a los botones dentro de la cuadrícula) Por lo tanto, no pude usar ninguna de las sugerencias anteriores. Finalmente esta es la solución que me funcionó. He agregado un evento onUnload en la etiqueta del cuerpo de _Layout.cshtml. Algo como esto:

<body onUnload="LogOff()">

y luego agregue la función LogOff para redirigir a Account / LogOff, que es un método incorporado en Asp.Net MVC. Ahora, cuando cierro el navegador o la pestaña, redirige al método LogOff y el usuario debe iniciar sesión cuando regrese. Lo he probado en Chrome y Firefox. ¡Y funciona!

  function LogOff() {
        $.ajax({
            url: "/Account/LogOff",
            success: function (result) {

                                        }
               });
       }

0
window.onbeforeunload = function ()
{       

    if (isProcess > 0) 
    {
        return true;       
    }   

    else
    { 
        //do something      
    }
}; 

Esta función muestra un cuadro de diálogo de confirmación si cierra una ventana o actualiza la página durante cualquier proceso en el navegador. Esta función funciona en todos los navegadores. Debe configurar isProcess var en su proceso ajax.


muestra completa para el conjunto isProcess?
Kiquenet

0
window.addEventListener("beforeunload", function (e) {
 var confirmationMessage = "tab close";

 (e || window.event).returnValue = confirmationMessage;     //Gecko + IE
 sendkeylog(confirmationMessage);
 return confirmationMessage;                                //Webkit, Safari, Chrome etc.
}); 

En realidad, quería mostrar un mensaje de confirmación si el usuario cierra la pestaña y SOLO. Esto es trabajo para mí. Pero estoy frente a un problema que, si estoy haciendo clic en cualquier enlace de la misma página, entonces también su confirmación mostrando message.For Moe se refieren: w3schools.com/code/tryit.asp?filename=FEK2KWUN9R8Z @Tunaki
Mohammed

1
lo que es sendkeylog?
Kiquenet

0

Como @jAndy mencionó, no hay un código JavaScript adecuado para detectar que se está cerrando una ventana. Partí de lo que @Syno había propuesto.

Pasé por una situación como esa y si sigues estos pasos, podrás detectarlo.
Lo probé en Chrome 67+ y Firefox 61+.

var wrapper = function () { //ignore this

var closing_window = false;
$(window).on('focus', function () {
    closing_window = false; 
   //if the user interacts with the window, then the window is not being 
   //closed
});

$(window).on('blur', function () {

    closing_window = true;
    if (!document.hidden) { //when the window is being minimized
        closing_window = false;
    }
    $(window).on('resize', function (e) { //when the window is being maximized
        closing_window = false;
    });
    $(window).off('resize'); //avoid multiple listening
});

$('html').on('mouseleave', function () {
    closing_window = true; 
    //if the user is leaving html, we have more reasons to believe that he's 
    //leaving or thinking about closing the window
});

$('html').on('mouseenter', function () {
    closing_window = false; 
    //if the user's mouse its on the page, it means you don't need to logout 
    //them, didn't it?
});

$(document).on('keydown', function (e) {

    if (e.keyCode == 91 || e.keyCode == 18) {
        closing_window = false; //shortcuts for ALT+TAB and Window key
    }

    if (e.keyCode == 116 || (e.ctrlKey && e.keyCode == 82)) {
        closing_window = false; //shortcuts for F5 and CTRL+F5 and CTRL+R
    }
});

// Prevent logout when clicking in a hiperlink
$(document).on("click", "a", function () {
    closing_window = false;
});

// Prevent logout when clicking in a button (if these buttons rediret to some page)
$(document).on("click", "button", function () {
    closing_window = false;

});
// Prevent logout when submiting
$(document).on("submit", "form", function () {
    closing_window = false;
});
// Prevent logout when submiting
$(document).on("click", "input[type=submit]", function () {
    closing_window = false;
});

var toDoWhenClosing = function() {

    //write a code here likes a user logout, example: 
    //$.ajax({
    //    url: '/MyController/MyLogOutAction',
    //    async: false,
    //    data: {

    //    },
    //    error: function () {
    //    },
    //    success: function (data) {
    //    },
    //});
};


window.onbeforeunload = function () {
    if (closing_window) {
        toDoWhenClosing();
    }
};

};


1
Tiene algunos problemas en su código javascript. Lo primero que noté es que te unirás continuamente resizecuando la ventana esté borrosa. Si se vuelve borroso 100x, entonces tendrás 100 oyentes, lo que terminará ralentizando el navegador.
Kyle

Puse un $ (ventana) .off ('cambiar tamaño'), ¿sería esto suficiente?
Bruno Henrique

Técnicamente, pero también eliminará cualquier otro controlador que se haya agregado en otro lugar a través de jQuery.
Kyle

-2

prueba esto, estoy seguro de que esto funcionará para ti.

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type='text/javascript'>
    $(function() {

        try{
            opera.setOverrideHistoryNavigationMode('compatible');
            history.navigationMode = 'compatible';
        }catch(e){}

        function ReturnMessage()
        {
            return "wait";
        }

        function UnBindWindow()
        {
            $(window).unbind('beforeunload', ReturnMessage);
        }

        $(window).bind('beforeunload',ReturnMessage );
    });
</script>

-3

Prueba esto. Funcionará. El método de descarga jquery está desactualizado.

window.onbeforeunload = function(event) {
    event.returnValue = "Write something clever here..";
};
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.