Como capturar o evento de fechamento da janela do navegador?

149

Quero capturar o evento de fechamento da janela / guia do navegador. Eu tentei o seguinte com jQuery:

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

Mas funciona também no envio de formulários, o que não é o que eu quero. Eu quero um evento que dispara apenas quando o usuário fecha a janela.

khelll
fonte

Respostas:

212

O beforeunloadevento é acionado sempre que o usuário sai da sua página por qualquer motivo.

Por exemplo, ele será acionado se o usuário enviar um formulário, clicar em um link, fechar a janela (ou guia) ou for para uma nova página usando a barra de endereços, a caixa de pesquisa ou um marcador.

Você pode excluir envios de formulários e hiperlinks (exceto de outros quadros) com o seguinte 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 versões do jQuery anteriores a 1.7, tente o seguinte:

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

O livemétodo não funciona com o submitevento, portanto, se você adicionar um novo formulário, precisará vincular o manipulador a ele também.

Observe que se um manipulador de eventos diferente cancelar o envio ou a navegação, você perderá o prompt de confirmação se a janela for fechada mais tarde. Você pode corrigir isso através da gravação do tempo nos submite clickeventos, e verificar se o beforeunloadacontece mais do que um par de segundos mais tarde.

SLaks
fonte
8
sim, trabalhando muito bem! As versões mais recentes do jquery suportam $ ('form'). Live ('submit, function () {}).
Venkat D.
4
Sua solução é boa, mas como cancelo o evento em caso de atualização? Eu quero o evento apenas se o navegador estiver fechado, sem atualização
Refael 22/10
Parece que o navegador exibe o valor de retorno de beforeunload como uma caixa de diálogo de confirmação. Então eu acho que esta resposta é mais preciso: ligação
tahagh
2
faz esta atualização cabo de uma página usando Ctrl + r, F5, Ctrl + Shift + re alterando a URL do navegador?
Arti
1
@ Jonny: Agora é só .on().
SLaks
45

Talvez apenas desvincule o beforeunloadmanipulador de eventos no manipulador de eventos do formulário submit:

jQuery('form').submit(function() {
    jQuery(window).unbind("beforeunload");
    ...
});
karim79
fonte
3
Não é tão fácil não usar o jQuery especificando isso na definição da tag do formulário? : `<Form onsubmit = "window.onbeforeunload = null;">
temor
4
@we Mas você precisaria incluir isso onsubmit=...em cada formulário. (I ter muitas formas por página, em uma determinada aplicação web)
KajMagnus
16

Para uma solução entre navegadores (testada no Chrome 21, IE9, FF15), considere usar o código a seguir, que é uma versão ligeiramente aprimorada do 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;
}); 

Observe que, desde o Firefox 4, a mensagem "Deseja realmente fechar?" não é exibido. FF apenas exibe uma mensagem genérica. Veja a nota em https://developer.mozilla.org/en-US/docs/DOM/window.onbeforeunload

desm
fonte
3
Este funciona de forma consistente nos navegadores. Apenas uma nota rápida; Atualizei liveas bindinstruções e para on, o que funciona muito bem com o nível mais recente do jQuery. Obrigado!
Sablefoste 31/01
16
window.onbeforeunload = function () {
    return "Do you really want to close?";
};
Behnam Mohammadi
fonte
4

Para uma solução que funcionou bem com controles de terceiros, como Telerik (por exemplo: RadComboBox) e DevExpress que usam as tags Anchor por vários motivos, considere usar o código a seguir, que é uma versão ligeiramente aprimorada do código da desm com um seletor melhor para si próprio segmentação por tags âncora:

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
fonte
1
Esta resposta está correta, mas para aqueles que tiveram problemas com este evento que acontece quando você atualizar a mudança do navegador que seu caso com o seguinte código: if (inFormOrLink == indefinido && inFormOrLink!)
LeonPierre
4

Minha resposta tem como objetivo fornecer referências simples.

COMO

Veja a resposta @SLaks .

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

Quanto tempo o navegador leva para finalmente desligar sua página?

Sempre que um usuário fecha a página ( xbotão ou CTRL+ W), o navegador executa o beforeunloadcódigo fornecido , mas não por tempo indeterminado. A única exceção é a caixa de confirmação (return 'Do you really want to close? ) que aguardará a resposta do usuário.

Chrome : 2 segundos.
Firefox : ∞ (ou clique duas vezes ou force para fechar)
Borda : ∞ (ou clique duas vezes)
Explorer 11 : 0 segundos.
Safari : TODO

O que usamos para testar isso:

  • Um servidor Node.js Express com log de solicitações
  • O seguinte arquivo HTML curto

O que ele faz é enviar o maior número possível de solicitações antes que o navegador encerre sua página (de forma síncrona).

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

Saída do 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.
zurfyx
fonte
3

Eu usei a resposta do Slaks, mas isso não estava funcionando como está, pois o onBeforeunload returnValue é analisado como uma sequência e exibido na caixa de confirmações do navegador. Portanto, o valor true foi exibido, como "true".

Apenas usando o retorno funcionou. Aqui está o meu código

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

Talvez você possa manipular o OnSubmit e definir um sinalizador que depois verifique no seu manipulador OnBeforeUnload.

i_am_jorf
fonte
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?";
                          }
                      })
Homem de codificação
fonte
1

Infelizmente, seja um recarregamento, um redirecionamento de nova página ou o fechamento do navegador, o evento será acionado. Uma alternativa é capturar o ID que aciona o evento e, se for o formulário, não aciona nenhuma função e, se não for o ID do formulário, faça o que você deseja fazer quando a página for fechada. Não tenho certeza se isso também é possível diretamente e é tedioso.

Você pode fazer algumas pequenas coisas antes que o cliente feche a guia. O javascript detecta a guia fechar o navegador / fechar o navegador, mas se a sua lista de ações for grande e a guia fechar antes de terminar, você estará desamparado. Você pode experimentá-lo, mas com a minha experiência, não depende disso.

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

Se o envio do formulário os levar para outra página (como suponho que seja, daí o acionamento de beforeunload), você poderá tentar alterar o envio do formulário para uma chamada ajax. Dessa forma, eles não sairão da página quando enviarem o formulário e você poderá usar o beforeunloadcódigo de ligação conforme desejar.

idrumgood
fonte
0

Meu problema: o evento 'onbeforeunload' seria acionado apenas se houvesse um número ímpar de envios (cliques). Eu tive uma combinação de soluções de threads semelhantes no SO para que minha solução funcionasse. bem, meu código falará.

<!--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
fonte
0

A partir do jQuery 1.7, o método .live () está obsoleto. Use .on () para anexar manipuladores de eventos. Usuários de versões mais antigas do jQuery devem usar .delegate () em vez de .live ()

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

no link completo ou

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

Tente isso também

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

Basta verificar ...

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
fonte
Isso não funciona. No momento em que o evento descarregar é acionado (btw, é acionado a partir do documento), o window.closed === false;
Sergey P. tcp azure
-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
fonte
-7

Seguir trabalhou para mim;

 $(window).unload(function(event) {
    if(event.clientY < 0) {
        //do whatever you want when closing the window..
    }
 });
Dilhan Jayathilaka
fonte
é uma função jquery.
Maxisam
7
O valor event.clientYé negativo se você clicar no botão Fechar do navegador ou no botão Fechar da guia. No entanto, esse valor é positivo quando você recarrega a página usando atalhos de teclado (F5, Ctrl-R) ou fecha o navegador usando atalhos de teclado (por exemplo, Alt-F4). Portanto, você não pode confiar na posição do evento para diferenciar o evento de fechamento do navegador do evento de recarregamento da página.
Julien Kronegg