Como substituir a caixa de diálogo OnBeforeUnload e substituí-la pela minha?

346

Preciso avisar os usuários sobre alterações não salvas antes de deixarem uma página (um problema bastante comum).

window.onbeforeunload=handler

Isso funciona, mas gera uma caixa de diálogo padrão com uma mensagem padrão irritante que envolve meu próprio texto. Eu preciso substituir completamente a mensagem padrão, para que meu texto seja claro ou (melhor ainda) substituir toda a caixa de diálogo por uma caixa de diálogo modal usando jQuery.

Até agora, falhei e não encontrei mais ninguém que pareça ter uma resposta. Isso é possível?

Javascript na minha página:

<script type="text/javascript">   
   window.onbeforeunload=closeIt;
</script>

A função closeIt ():

function closeIt()
{
  if (changes == "true" || files == "true")
  {
      return "Here you can append a custom message to the default dialog.";
  }
}

Usando jQuery e jqModal, tentei esse tipo de coisa (usando um diálogo de confirmação personalizado):

$(window).beforeunload(function() {
        confirm('new message: ' + this.href + ' !', this.href);
        return false;
    });

o que também não funciona - não consigo vincular o evento beforeunload.

carne
fonte
11
você pode dar um exemplo do seu código atual e o que ele produz?
Owen
Owen está correto. E, a razão por trás disso é a segurança. Impedir o descarregamento de uma página é útil em formulários da Web e outros, mas pode ser facilmente explorado por um site mal-intencionado para enganar o usuário e permanecer em uma página. É por isso que os navegadores da web implementam a mensagem padrão e têm esse mecanismo para inserir texto personalizado.
pluckyglen
veja aqui para obter mais informações: stackoverflow.com/questions/140460
Ben McIntyre
11
não é possível no chrome, referência: stackoverflow.com/questions/37782104/…
Abhijeet

Respostas:

299

Você não pode modificar o diálogo padrão para onbeforeunload, portanto, sua melhor aposta pode ser trabalhar com ele.

window.onbeforeunload = function() {
    return 'You have unsaved changes!';
}

Aqui está uma referência a isso da Microsoft:

Quando uma string é atribuída à propriedade returnValue de window.event, aparece uma caixa de diálogo que oferece aos usuários a opção de permanecer na página atual e manter a string que foi atribuída a ela. A instrução padrão que aparece na caixa de diálogo "Tem certeza de que deseja sair desta página? ... Pressione OK para continuar ou Cancelar para permanecer na página atual.", Não pode ser removida ou alterada.

O problema parece ser:

  1. Quando onbeforeunloadé chamado, o valor de retorno do manipulador será assumido como window.event.returnValue.
  2. Ele analisará o valor de retorno como uma sequência (a menos que seja nulo).
  3. Como falseé analisado como uma sequência, a caixa de diálogo será acionada, a qual passará um true/ apropriado false.

O resultado é, não parece ser uma maneira de atribuir falsea onbeforeunloadpara impedir que o diálogo padrão.

Notas adicionais sobre o jQuery:

  • A configuração do evento no jQuery pode ser problemática, pois isso permite que outros onbeforeunloadeventos ocorram também. Se você deseja apenas que o seu evento de descarregamento ocorra, devo usar o JavaScript simples.
  • O jQuery não possui um atalho para onbeforeunloadque você precise usar a bindsintaxe genérica .

    $(window).bind('beforeunload', function() {} );

Editar 09/04/2018 : as mensagens personalizadas nas caixas de diálogo onbeforeunload estão obsoletas desde o chrome-51 (cf: nota de versão )

Owen
fonte
20
Eu descobri que o exemplo JQuery de dado no final não funciona no firefox. Adote a maneira simples: window.onbeforeunload = function () {...}
jb.
21
Apenas uma observação de que o Firefox foi alterado recentemente, para que o texto na caixa de diálogo não possa ser personalizado: bugzilla.mozilla.org/show_bug.cgi?id=588292
David Hammond
15
Mas como o facebook fornece uma caixa de diálogo personalizada? por exemplo, vá para a página de mensagens, responda à mensagem do seu amigo e, em seguida, antes de clicar em enviar, tente clicar em outro link. você verá um pop
Varun
20
@Varun - notícias antigas, mas o Facebook estão possivelmente colocando manipuladores no evento click de todas as suas âncoras, mas se você reescrever o URL no navegador ou fechar a janela, ele reverterá para o método padrão sobre o qual eles não têm controle.
Tabloo Quijico
11
@Varun Também estou surpreso que esta resposta, que é impossível, seja sinalizada como resposta e tenha 150 votos positivos ... Acabei de perceber, a mensagem personalizada do FB está disponível apenas através de links dentro de seu site. Não se você simplesmente navegar para fora ...
Sébastien Richer
28

O que funcionou para mim, usando o jQuery e testado no IE8, Chrome e Firefox, é:

$(window).bind("beforeunload",function(event) {
    if(hasChanged) return "You have unsaved changes";
});

É importante não retornar nada se nenhum prompt for necessário, pois há diferenças entre o IE e outros comportamentos do navegador aqui.

mergulhão
fonte
Interessante, event.returnValueé o único método "aprovado" no IE. O IE continua dizendo "O valor dessa propriedade tem precedência sobre os valores retornados pela função, como por meio de uma instrução de retorno Microsoft JScript". .. seria bom ver uma correlação garantida entre return(de evento) e event.returnValue..
21

Embora não haja nada que você possa fazer sobre a caixa em algumas circunstâncias, você pode interceptar alguém clicando em um link. Para mim, valeu a pena o esforço para a maioria dos cenários e, como alternativa, deixei o evento de descarregamento.

Eu usei o Boxy em vez do Diálogo jQuery padrão, ele está disponível aqui: http://onehackoranother.com/projects/jquery/boxy/

$(':input').change(function() {
    if(!is_dirty){
        // When the user changes a field on this page, set our is_dirty flag.
        is_dirty = true;
    }
});

$('a').mousedown(function(e) {
    if(is_dirty) {
        // if the user navigates away from this page via an anchor link, 
        //    popup a new boxy confirmation.
        answer = Boxy.confirm("You have made some changes which you might want to save.");
    }
});

window.onbeforeunload = function() {
if((is_dirty)&&(!answer)){
            // call this if the box wasn't shown.
    return 'You have made some changes which you might want to save.';
    }
};

Você pode se conectar a outro evento e filtrar mais sobre que tipo de âncora foi clicada, mas isso funciona para mim e o que eu quero fazer e serve como um exemplo para outras pessoas usarem ou melhorarem. Pensei em compartilhar isso para aqueles que desejam esta solução.

Recortei o código, portanto, isso pode não funcionar como está.

Dan Power
fonte
return 'Você fez algumas alterações que talvez queira salvar.' não funcionou para mim. Eu tive que armazenar a mensagem em uma variável como 'warning_message' e retornei warning_message. Então só funcionou para mim!
Suganya
você testou no IE, Chrome, Firefox?
Kiquenet
9

1) Use onbeforeunload, não onunload.

2) O importante é evitar a execução de uma declaração de retorno. Com isso, não pretendo evitar retornar do seu manipulador. Você retorna bem, mas faz isso garantindo que você chegue ao final da função e NÃO execute uma declaração de retorno. Sob essas condições, o diálogo padrão interno não ocorre.

3) Você pode, se você usar onbeforeunload, executar uma chamada ajax em seu manipulador unbeforeunload para organizar o servidor, mas deve ser síncrono, e você deverá aguardar e manipular a resposta em seu manipulador onbeforeunload (ainda respeitando condição (2) acima). Eu faço isso e funciona bem. Se você fizer uma chamada ajax síncrona, tudo será mantido até a resposta voltar. Se você fizer uma assíncrona, pensando que não se importa com a resposta do servidor, o descarregamento da página continuará e sua chamada ajax será abortada por esse processo - incluindo um script remoto, se estiver em execução.

user1164763
fonte
Apenas FYI quem lê este ^ Chrome é depreciativo chamadas AJAX síncronos em unbeforeunload
morganwebdev
4

Tente colocar uma return;mensagem em vez de uma mensagem .. isso está funcionando para muitos navegadores para mim. (Isso realmente impede os presentes da caixa de diálogo)

window.onbeforeunload = function(evt) {            
        //Your Extra Code
        return;
}
Donald Powell
fonte
3
return null irá impedir de diálogo de abertura
Brett Weber
11
return null NÃO impedirá a abertura da caixa de diálogo. Eu tentei no Chrome e não é o caso.
Raio
2
Posso confirmar o comentário de Ray no IE também. Retornar nullabrirá uma caixa de diálogo com o texto "nulo". No entanto, return void(0);não abrirá a caixa de diálogo.
MCattle
11
Ao não colocar nenhuma instrução de retorno dentro da função beforeunload, a caixa de diálogo não será aberta.
OuuGiii
3

Você pode detectar qual botão (ok ou cancelar) pressionado pelo usuário, porque a função onunload é chamada apenas quando o usuário escolhe sair da página. Embora nesta função as possibilidades sejam limitadas, porque o DOM está sendo recolhido. Você pode executar o javascript, mas o POST do ajax não faz nada; portanto, você não pode usar esse método para o logout automático. Mas existe uma solução para isso. O window.open ('logout.php') é executado na função onunload, para que o usuário saia com uma nova janela.

function onunload = (){
    window.open('logout.php');
}

Esse código é chamado quando o usuário sai da página ou fecha a janela ativa e o usuário desconectado por 'logout.php'. A nova janela fecha imediatamente quando o logout php consiste em código:

window.close();
Tamas Cseh
fonte
Você pode usar uma postagem síncrona nas funções antes de descarregar e descarregar. Especialmente se você precisar de dados de volta do servidor. Qualquer código assíncrono dentro desses blocos pode não ser concluído no momento em que a página é descarregada.
precisa saber é o seguinte
3

Enfrentei o mesmo problema, estava bem em obter sua própria caixa de diálogo com a minha mensagem, mas o problema que enfrentei foi: 1) Ele estava dando uma mensagem em todas as navegações. Quero apenas um clique para fechar. 2) com minha própria mensagem de confirmação, se o usuário selecionar cancelar, ainda mostrará a caixa de diálogo padrão do navegador.

A seguir está o código de soluções que encontrei, que escrevi na minha página mestra.

function closeMe(evt) {
    if (typeof evt == 'undefined') {
        evt = window.event; }
    if (evt && evt.clientX >= (window.event.screenX - 150) &&
        evt.clientY >= -150 && evt.clientY <= 0) {
        return "Do you want to log out of your current session?";
    }
}
window.onbeforeunload = closeMe;
Imran Rizvi
fonte
1
 <script type="text/javascript">
        window.onbeforeunload = function(evt) {
            var message = 'Are you sure you want to leave?';
            if (typeof evt == 'undefined') {
                evt = window.event;
            }       
            if (evt) {
                evt.returnValue = message;
            }
            return message;
        } 
    </script>

consulte http://www.codeprojectdownload.com

Krishna Patel
fonte
1

Que tal usar a versão especializada do comando "bind" "one". Depois que o manipulador de eventos é executado pela primeira vez, é automaticamente removido como manipulador de eventos.

$(window).one("beforeunload", BeforeUnload);
Riga
fonte
certeza que isso é .no ( "beforeunload"
Sergiu Mindras
2
@SergiuMindras não, é .one()- que anexa um ouvinte de evento para ouvir o evento acontecer apenas uma vez: "Anexe um manipulador a um evento para os elementos. O manipulador é executado no máximo uma vez por elemento por tipo de evento". api.jquery.com/one
Sean Kendle
0

Abordagem angular 9:

constructor() {
    window.addEventListener('beforeunload', (event: BeforeUnloadEvent) => {
     if (this.generatedBarcodeIndex) {
      event.preventDefault(); // for Firefox
      event.returnValue = ''; // for Chrome
      return '';
     }
     return false;
    });
   }

Suporte a navegadores e remoção da mensagem personalizada:

  • O Chrome removeu o suporte para a mensagem personalizada na versão 51 min
  • O Opera removeu o suporte para a mensagem personalizada na versão 38 min
  • O Firefox removeu o suporte para a mensagem personalizada na versão 44.0 min
  • O Safari removeu o suporte para a mensagem personalizada na versão 9.1 min
Istvan Dembrovszky
fonte