Rileva la chiusura del browser o della scheda


306

Esiste un codice JavaScript / jQuery tra browser per rilevare se il browser o la scheda di un browser sono stati chiusi, ma non a causa del clic su un collegamento?


1
Vedi la mia risposta a questa domanda: stackoverflow.com/questions/3735198/…
Nivas


Usa sessionStorage proprietà, scadrà una volta chiuso il browser. w3schools.com/jsref/prop_win_sessionstorage.asp
csandreas1

Controlla questa risposta! L'ho trovato estremamente utile e copre la maggior parte dei casi. stackoverflow.com/a/26275621/7192927
SukanyaPai

Risposte:


273

Se ti ottengo correttamente, vuoi sapere quando una scheda / finestra viene effettivamente chiusa. Bene, AFAIK è l'unico modo Javascriptper rilevare quel tipo di cose onunloaded onbeforeunloadeventi.

Sfortunatamente (o per fortuna?), Quegli eventi vengono attivati ​​anche quando si lascia un sito tramite linkil pulsante Indietro del browser. Quindi questa è la migliore risposta che posso dare, non credo che tu possa rilevare nativamente un puro closein Javascript. Correggimi se sbaglio qui.


39
Corretta. È possibile rilevare solo quando la pagina viene scaricata, non quando la finestra è chiusa. Inoltre, onbeforeunload non è standard, quindi non è supportato da tutti i browser.
Guffa,

7
Volevo usare anche la funzione 'alla chiusura', ma ho notato che i miei utenti a volte aggiornano lo schermo premendo F5. Dato che i miei gestori "on close" vengono richiamati su tale aggiornamento, ciò significa che non posso usarlo nel modo in cui ne avevo bisogno (che era una vera "scheda o finestra chiusa") ... dannazione, abbiamo bisogno di un nuovo modello di eventi per tutto questo!
Jeach,

1
Non funziona più su Chrome / Opera ... chromestatus.com/feature/5349061406228480
Samir Seetal

2
Ovviamente funzionerà ancora, hanno appena rimosso un Stringvalore di ritorno personalizzato da onbeforeunload. Quindi ora non puoi più visualizzare un messaggio personalizzato prima di scaricare.
jAndy,

@jAndy @Guffa Come posso sapere quale finestra è stata attivata unload?
Egor Dudyak,

125

Dalla documentazione di Firefox

Per alcuni motivi, i browser basati su Webkit non seguono le specifiche per la finestra di dialogo. Un esempio quasi trasversale sarebbe vicino all'esempio seguente.

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

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

Questo esempio per la gestione di tutti i browser.


2
Questa è l'unica soluzione che ha funzionato per il mio browser Chrome. Non ho provato nessun altro.
Chase Roberts,

4
Sì, provo molte soluzioni e alla fine ne vengo insieme, combinazione per le migliori risposte, e lo collaudo su tutti i browser.
Mohamed-Ibrahim,

1
Questo metodo non funziona perfettamente alla chiusura della scheda durante l'utilizzo di Firefox (> = ver. 44) con solo la scheda aperta.
Rajkishore,

Ad oggi, utilizzando tutte le ultime versioni dei browser, il prompt funziona quando si chiude la scheda, si allontana o si chiude il browser per Chrome, Firefox, Opera, IE11 e Edge e funziona anche quando si hanno più schede aperte ad eccezione di Chrome in cui Chrome chiude tutte le schede senza sollecitare, almeno sulla mia macchina.
Thierry,

non dare un vero out come definito in questione. Ciò ha anche attivato l'evento di congedo di pagina non solo la chiusura del browser o la chiusura della scheda
Sunil Acharya,

48

Soluzione semplice

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

7
Che tipo di stregoneria è questa? (y) funziona su tutti i browser? funziona alla grande su Chrome
Ziv Weissman

5
si attiva quando si aggiorna la pagina. questo è il mio unico problema.
Leo Leoncio,

6
Questa soluzione non è più disponibile su Firefox e Chrome
Mehdi Dehghani,

Questo ha anche attivato l'evento di congedo di pagina non solo la chiusura del browser o la chiusura della scheda
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') ;
    }   
}

// Funziona in IE7, se chiudi la scheda o il browser con una sola scheda


2
ya. ma per browser con più schede come ie8, firefox. c'è un problema con questo?
cometta,

Si scopre che l'utilizzo di questo codice in IE9 farà apparire questo messaggio quando l'utente fa clic sui pulsanti indietro, avanti o aggiorna con il mouse.
Steve Wortham,

Solo un avvertimento che abbiamo implementato una soluzione simile nel 2007. Questa soluzione non funziona più in IE9 circa una settimana fa. Ha smesso di funzionare (o forse non ha mai funzionato) nei browser a schede molto tempo fa.
tjfo,

Ho iniettato window.onunload = "alert('wait')"e window.onbeforeunload = "alert('wait... chrome!')"usando la console in Chromium / Ubuntu ma nessuno dei due ha sparato quando ho chiuso la scheda.
acqua ghiacciata,

window.onunload = "alert('wait')"e cose del genere non dovrebbero funzionare davvero. "La funzione dovrebbe assegnare un valore di stringa alla proprietà returnValue dell'oggetto Event e restituire la stessa stringa".
Dai

8

Avevo bisogno di disconnettere automaticamente l'utente quando il browser o la scheda si chiudono, ma non quando l'utente passa ad altri collegamenti. Inoltre, non volevo che fosse visualizzato un messaggio di conferma quando ciò accade. Dopo aver lottato con questo per un po ', specialmente con IE e Edge, ecco cosa ho finito di fare (ho controllato lavorando con IE 11, Edge, Chrome e Firefox) dopo aver basato l'approccio con questa risposta .

Innanzitutto, avvia un conto alla rovescia sul server nel beforeunloadgestore eventi in JS. Le chiamate ajax devono essere sincrone affinché IE e Edge funzionino correttamente. È inoltre necessario utilizzare return;per impedire che la finestra di dialogo di conferma venga visualizzata in questo modo:

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

L'avvio del timer imposta il cancelLogoutflag su false . Se l'utente aggiorna la pagina o passa a un altro collegamento interno, il cancelLogoutflag sul server è impostato su true . Una volta scaduto l'evento timer, controlla il cancelLogoutflag per vedere se l'evento di logout è stato annullato. Se il timer è stato annullato, lo arresterebbe. Se il browser o la scheda fossero chiusi, la cancelLogoutbandiera rimarrebbe falsa e il gestore eventi disconnetterebbe l'utente.

Nota di implementazione: sto utilizzando ASP.NET MVC 5 e sto annullando il logout in un Controller.OnActionExecuted()metodo ignorato .


Questo ha funzionato alla grande. C'è una ragione per cui fai "asincrono: falso"? Ciò genera avvisi che le chiamate AJAX sincrone sono obsolete. Grazie!
cat_in_hat il

1
@FoundWaldoException, come indicato nella risposta, ho scoperto che l'asincronizzazione doveva essere impostata su false affinché funzionasse in IE ed Edge.
Ionian316,

Come annullare la disconnessione OnActionExecuted?
Kiquenet,

@Kiquenet Basta fermare il timer che è stato avviato nel tuo codice.
Ionian316,

6

Spiacenti, non sono stato in grado di aggiungere un commento a una delle risposte esistenti, ma nel caso in cui volessi implementare una sorta di finestra di avviso, volevo solo menzionare che qualsiasi funzione del gestore di eventi ha un argomento - evento. Nel tuo caso puoi chiamare event.preventDefault () per impedire di lasciare la pagina automaticamente, quindi aprire la tua finestra di dialogo. Considero questa un'opzione molto migliore rispetto all'utilizzo di un avviso standard brutto e insicuro (). Ho implementato personalmente il mio set di finestre di dialogo basate sull'oggetto kendoWindow (l'interfaccia utente Kendo di Telerik, che è quasi completamente open-source, ad eccezione di kendoGrid e kendoEditor). È inoltre possibile utilizzare finestre di dialogo dall'interfaccia utente di jQuery. Si noti, tuttavia, che tali elementi sono asincroni e sarà necessario associare un gestore all'evento onclick di ogni pulsante, ma è abbastanza facile da implementare.

Tuttavia, concordo sul fatto che la mancanza del vero evento di chiusura sia terribile: se, ad esempio, si desidera ripristinare lo stato della sessione sul back-end solo in caso di chiusura reale, è un problema.


6

Per attività simili, è possibile utilizzare sessionStorageper archiviare i dati localmente fino alla chiusura della scheda del browser.

L' sessionStorageoggetto memorizza i dati per una sola sessione (i dati vengono eliminati alla chiusura della scheda del browser). ( W3Schools )

Questa è la mia penna .

<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

Non esiste alcun evento, ma esiste una proprietà window.closedche è supportata in tutti i principali browser al momento della stesura di questo documento. Quindi, se davvero avessi bisogno di sapere, potresti eseguire il polling della finestra per controllare quella proprietà.

if(myWindow.closed){do things}

Nota: il polling di qualsiasi cosa non è generalmente la soluzione migliore. L' window.onbeforeunloadevento dovrebbe essere usato se possibile, l'unico avvertimento è che spara anche se navighi via.


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

9
Questo non funzionerà su Firefox o Chrome. Prova beforeunloadse vuoi visualizzare un avviso. In questo modo:$(window).on('beforeunload', function(){ alert ('Bye now')});
AdrianoRR il

5
come da documenti jQuery "La maggior parte dei browser ignorerà le chiamate a alert (), confirm () e prompt ()" api.jquery.com/unload
katzmopolitan

4

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

Ho trovato un modo che funziona su tutti i miei browser .

Testato sulle seguenti versioni: Firefox 57, Internet Explorer 11, Edge 41, uno degli ultimi Chrome (non mostrerà la mia versione)

Nota : onbeforeunload si attiva se si lascia la pagina in qualsiasi modo possibile (aggiorna, chiudi il browser, reindirizza, collega, invia ..). Se si desidera che accada solo alla chiusura del browser, è sufficiente associare i gestori di eventi.

  $(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
            }
        };

  });

Come verrà aggiunto un gestore separato per la chiusura del browser ... Non credo che abbiamo un evento separato per questo.
blazehub,

Questo è stato molto utile. Avevo bisogno di regolare l'ancora A per sparare solo per i collegamenti ipertestuali reali. Altrimenti, facendo clic sulle schede bootstrap è incasinato: $ ("a [href! = '']"). Not ('[href ^ = "#"]'). Bind ("click", function ()
Ken Forslund

3

Dato che nessuno lo ha ancora menzionato (più di 8 anni dopo): un WebSocket può essere un altro modo efficace per rilevare una scheda chiusa. Finché la scheda è aperta e puntata verso l'host, il client è in grado di mantenere una connessione WebSocket attiva all'host.

Avvertenza: si noti che questa soluzione è realmente praticabile per un progetto solo se un WebSocket non richiede alcun sovraccarico significativo aggiuntivo da quello che si sta già facendo.

Entro un ragionevole periodo di timeout (ad es. 2 minuti), il lato server può determinare che il client è andato via dopo che WebSocket si è disconnesso ed eseguire qualsiasi azione desiderata come la rimozione di file temporanei caricati. (Nel mio caso d'uso estremamente specializzato, il mio obiettivo era quello di terminare un server di app localhost tre secondi dopo l'interruzione della connessione WebSocket e la chiusura di tutte le attività CGI / FastCGI - qualsiasi altra connessione keep-alive non mi riguarda.)

Ho avuto problemi a far funzionare correttamente il gestore di eventi onunload con i beacon (come raccomandato da questa risposta ). La chiusura della scheda non sembra attivare il beacon e le schede aperte lo attivano in modi che potrebbero potenzialmente causare problemi. Un WebSocket ha risolto il problema che stavo incontrando in modo più pulito perché la connessione si chiude all'incirca nello stesso momento in cui la scheda si chiude e il cambio di pagina all'interno dell'applicazione apre semplicemente una nuova connessione WebSocket all'interno della finestra di ritardo.


2
va bene. Ma non puoi condividere alcun codice o procedura per gestirlo? Senza quello per un noob come me non riesco a capire
P Satish Patro

In realtà, non ero chiaro nel mio primo commento. Non conosco il socket web. Quindi, volevo solo vedere come gestire
P Satish Patro

1
Il link nel mio commento sopra va ad alcuni esempi di codice JS WebSocket. La parte client JS è la parte facile. Questo codice è per il mio caso d'uso molto specifico, anche se ho bisogno di terminare l'intero server delle applicazioni in modo tempestivo. Il modo in cui scrivi un server WebSocket dipende da te e richiede una configurazione lato server per connettere tutto (molte persone preferiscono un backend NodeJS con un frontend Nginx). La scrittura di un server abilitato TCP / IP è un argomento complesso non adatto alla discussione nei commenti ed è eccessivo crearne uno solo per rilevare questo particolare problema.
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());
  }
});

JSFiddle Link

Ciao a tutti, sono stato in grado di ottenere clic su "Rileva browser e Tab Close Event" utilizzando la memoria locale del browser e il timestamp. Spero che tutti voi risolverete i vostri problemi usando questa soluzione.

Dopo la mia ricerca iniziale ho scoperto che quando chiudiamo un browser, il browser chiuderà tutte le schede una per una per chiudere completamente il browser. Quindi, ho osservato che ci sarà pochissimo ritardo tra la chiusura delle schede. Quindi ho preso questo ritardo come il mio principale punto di convalida e in grado di ottenere il rilevamento degli eventi di chiusura del browser e della scheda.

L'ho testato sulla versione 76.0.3809.132 del browser Chrome e l'ho trovato funzionante

:) Vota se hai trovato utile la mia risposta ....


Bene, questo mi ha dato un'idea. Sto impostando un timestamp più 10 secondi nell'archivio locale dopo il login e prima dell'evento da scaricare. Al caricamento, verifico se il tempo è passato, quindi reindirizzo alla pagina di accesso. Grazie :)
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 usernon lo fa, su Firefox, ma lo fa in Chrome ...
TrySpace

Qualsiasi valore di ritorno (stringa) viene visualizzato solo in MSIE <= 11. Quindi sostanzialmente inutile per tutti gli altri browser.
OSWorX

1

È possibile verificarlo con l'aiuto di window.closed in un gestore di eventi su un evento di scaricamento come questo, ma è richiesto l'utilizzo del timeout (quindi il risultato non può essere garantito se il ritardo smth o impedisce la chiusura della finestra):

Esempio di JSFiddle (testato su Safari 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

Ho provato tutte le soluzioni di cui sopra, nessuna di queste ha funzionato davvero per me, specialmente perché ci sono alcuni componenti di Telerik nel mio progetto che hanno il pulsante "Chiudi" per le finestre popup e chiama l'evento "beforeunload". Inoltre, il selettore di pulsanti non funziona correttamente quando nella tua pagina è presente la griglia di Telerik (intendo i pulsanti all'interno della griglia) Quindi, non ho potuto utilizzare nessuno dei suggerimenti sopra. Finalmente questa è la soluzione che ha funzionato per me. Ho aggiunto un evento onUnload sul tag body di _Layout.cshtml. Qualcosa come questo:

<body onUnload="LogOff()">

e quindi aggiungere la funzione LogOff per reindirizzare a Account / LogOff che è un metodo integrato in Asp.Net MVC. Ora, quando chiudo il browser o la scheda, reindirizza al metodo LogOff e l'utente deve effettuare il login quando ritorna. L'ho testato su Chrome e Firefox. E funziona!

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

                                        }
               });
       }

0
window.onbeforeunload = function ()
{       

    if (isProcess > 0) 
    {
        return true;       
    }   

    else
    { 
        //do something      
    }
}; 

Questa funzione mostra una finestra di dialogo di conferma se chiudi la finestra o aggiorni la pagina durante qualsiasi processo nel browser. Questa funzione funziona in tutti i browser. Devi impostare isProcess var nel tuo processo ajax.


campione completo per set 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.
}); 

In realtà volevo mostrare il messaggio di conferma se l'utente chiudeva la scheda SOLO. Questo funziona per me. Ma sto affrontando un problema che, se faccio clic su uno dei collegamenti della stessa pagina, viene visualizzato anche un messaggio di conferma. Per ulteriori informazioni, consultare: w3schools.com/code/tryit.asp?filename=FEK2KWUN9R8Z @Tunaki
Mohammed

1
che cos'è sendkeylog?
Kiquenet,

0

Come accennato da @jAndy, non esiste un codice javascript appropriato per rilevare la chiusura di una finestra. Sono partito da ciò che @Syno aveva proposto.

Avevo superato una situazione del genere e, purché tu seguissi questi passaggi, sarai in grado di rilevarla.
L'ho provato su Chrome 67+ e 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
Hai dei problemi nel tuo codice javascript. La prima cosa che ho notato è che ti legherai continuamente resizequando la finestra è sfocata. Se viene sfocato 100x, avrai 100 ascoltatori, che finiranno per rallentare il browser.
Kyle,

Ho messo un $ (finestra) .off ('ridimensiona'), sarebbe abbastanza?
Bruno Henrique,

Tecnicamente, ma rimuoverà anche tutti gli altri gestori che sono stati aggiunti altrove tramite jQuery.
Kyle,

-2

prova questo, sono sicuro che funzionerà per te.

<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

Prova questo. Funzionerà. il metodo di scarico jquery è obsoleto.

window.onbeforeunload = function(event) {
    event.returnValue = "Write something clever here..";
};
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.