Come acquisire l'evento di chiusura della finestra del browser?


149

Voglio catturare l'evento di chiusura della finestra / scheda del browser. Ho provato quanto segue con jQuery:

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

Ma funziona anche con l'invio di moduli, che non è quello che voglio. Voglio un evento che si attiva solo quando l'utente chiude la finestra.

Risposte:


212

L' beforeunloadevento si attiva ogni volta che l'utente lascia la tua pagina per qualsiasi motivo.

Ad esempio, verrà attivato se l'utente invia un modulo, fa clic su un collegamento, chiude la finestra (o la scheda) o accede a una nuova pagina utilizzando la barra degli indirizzi, la casella di ricerca o un segnalibro.

È possibile escludere invii di moduli e collegamenti ipertestuali (tranne che da altri frame) con il seguente codice:

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; 
})

Per le versioni jQuery precedenti alla 1.7, prova questo:

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; 
})

Il livemetodo non funziona con l' submitevento, quindi se aggiungi un nuovo modulo, dovrai associare anche il gestore.

Nota che se un diverso gestore eventi annulla l'invio o la navigazione, perderai la richiesta di conferma se la finestra verrà effettivamente chiusa in seguito. Si potrebbe rimediare registrando il tempo in submite clickmanifestazioni, e controllando se l' beforeunloadaccade più di un paio di secondi più tardi.


8
sì, funziona alla grande! Le versioni più recenti di jquery supportano $ ('form'). Live ('submit, function () {}).
Venkat D.

4
La tua soluzione è valida, ma come posso annullare l'evento in caso di aggiornamento? Voglio l'evento solo se il browser è chiuso, nessun caso di aggiornamento
Refael,

Sembra che il browser visualizzi il valore restituito da beforeunload come una finestra di dialogo di conferma. Quindi penso che questa risposta sia più precisa: link
tahagh

2
fa questo aggiornamento maniglia di una pagina utilizzando Ctrl + r, F5, Ctrl + Shift + re cambiando l'URL del browser?
Arti

1
@Jonny: ora è giusto .on().
SLaks,

45

Forse basta separare il beforeunloadgestore eventi all'interno del gestore eventi del modulo submit:

jQuery('form').submit(function() {
    jQuery(window).unbind("beforeunload");
    ...
});

3
Non è altrettanto facile non usare jQuery specificandolo nella definizione del tag del modulo? : `<form onsubmit =" window.onbeforeunload = null; ">
timore re

4
@awe Ma dovresti includerlo onsubmit=...in ogni modulo. (Ho molte forme per pagina, in una certa webapp)
KajMagnus,

16

Per una soluzione cross-browser (testata in Chrome 21, IE9, FF15), considera l'utilizzo del seguente codice, che è una versione leggermente modificata del codice di 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;
}); 

Si noti che da Firefox 4, il messaggio "Vuoi davvero chiudere?" non viene visualizzato. FF visualizza solo un messaggio generico. Vedi nota in https://developer.mozilla.org/en-US/docs/DOM/window.onbeforeunload


3
Questo funziona in modo coerente su tutti i browser. Solo una breve nota; Ho aggiornato sia il livee le binddichiarazioni on, che funziona alla grande con l'ultimo livello di jQuery. Grazie!
Sablefoste,


4

Per una soluzione che ha funzionato bene con controlli di terze parti come Telerik (es .: RadComboBox) e DevExpress che utilizzano i tag Anchor per vari motivi, considera l'utilizzo del seguente codice, che è una versione leggermente modificata del codice di desm con un selettore migliore per sé targeting tag di ancoraggio:

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;
});

1
Questa risposta è corretta ma per coloro che hanno avuto problemi con questo evento durante l'aggiornamento del browser, cambia il tuo if nel seguente codice: if (inFormOrLink! == undefined &&! InFormOrLink)
LeonPierre

4

La mia risposta mira a fornire parametri di riferimento semplici.

COME

Vedi la risposta di @SLaks .

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

Quanto tempo impiega il browser a chiudere definitivamente la pagina?

Ogni volta che un utente chiude la pagina ( xpulsante o CTRL+ W), il browser esegue il beforeunloadcodice specificato, ma non indefinitamente. L'unica eccezione è la casella di conferma ( return 'Do you really want to close?) che attenderà fino alla risposta dell'utente.

Chrome : 2 secondi.
Firefox : ∞ (o doppio clic o forza alla chiusura)
Bordo : ∞ (o doppio clic)
Explorer 11 : 0 secondi.
Safari : TODO

Cosa abbiamo usato per testarlo:

  • Un server Node.js Express con registro delle richieste
  • Il seguente breve file HTML

Ciò che fa è inviare quante più richieste possibile prima che il browser chiuda la sua pagina (in modo sincrono).

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

Uscita Chrome:

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.

3

Ho usato Slaks answer ma non funzionava così com'è, poiché onbeforeunload returnValue viene analizzato come una stringa e quindi visualizzato nella casella di conferma del browser. Quindi è stato visualizzato il valore vero, come "vero".

Solo usando return ha funzionato. Ecco il mio codice

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;
})

1

Forse potresti gestire OnSubmit e impostare un flag che successivamente controllerai nel tuo gestore OnBeforeUnload.


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?";
                          }
                      })

1

Sfortunatamente, si tratterà di ricaricare, reindirizzare una nuova pagina o chiudere il browser. Un'alternativa è catturare l'id che attiva l'evento e se è un modulo non attivare alcuna funzione e se non è l'id del modulo, fai quello che vuoi fare quando la pagina si chiude. Non sono sicuro che sia possibile anche direttamente ed è noioso.

Puoi fare alcune piccole cose prima che il cliente chiuda la scheda. javascript rileva il browser chiudi la scheda / chiudi il browser ma se la tua lista di azioni è grande e la scheda si chiude prima che sia finita sei impotente. Puoi provarlo ma con la mia esperienza non dipendere da esso.

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


0

Se l'invio del modulo li porta a un'altra pagina (come presumo, quindi l'attivazione di beforeunload), è possibile provare a modificare l'invio del modulo in una chiamata Ajax. In questo modo, non lasceranno la tua pagina quando invieranno il modulo e potrai usare il tuo beforeunloadcodice vincolante come desideri.


0

Il mio problema: l'evento "onbeforeunload" verrebbe attivato solo in presenza di un numero dispari di invii (clic). Ho avuto una combinazione di soluzioni da thread simili in SO per far funzionare la mia soluzione. bene il mio codice parlerà.

<!--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');   
}

0

A partire da jQuery 1.7, il metodo .live () è obsoleto. Utilizzare .on () per collegare i gestori di eventi. Gli utenti di versioni precedenti di jQuery dovrebbero utilizzare .delegate () in preferenza a .live ()

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

su completo o collegamento

$(window).unbind();

0

Prova anche questo

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

-1

Verifica solo ...

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");
    }
  }
}

Non funziona Al momento viene generato l'evento di scarico (tra l'altro, viene generato dal documento), window.closed === false;
Sergey P. aka azzurro il

-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`

-7

Il seguito ha funzionato per me;

 $(window).unload(function(event) {
    if(event.clientY < 0) {
        //do whatever you want when closing the window..
    }
 });

è una funzione jquery.
maxisam,

7
Il event.clientYè negativo se si fa clic sul pulsante di chiusura pulsante del browser vicino o sulla scheda. Tuttavia, questo valore è positivo quando si ricarica la pagina utilizzando le scorciatoie da tastiera (F5, Ctrl-R) o si chiude il browser utilizzando le scorciatoie da tastiera (ad esempio Alt-F4). Pertanto, non è possibile fare affidamento sulla posizione dell'evento per differenziare l'evento di chiusura del browser dall'evento di ricaricamento della pagina.
Julien Kronegg,
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.