Existe um evento de carga entre navegadores ao clicar no botão Voltar?

185

Para todos os principais navegadores (exceto o IE), o onloadevento JavaScript não é acionado quando a página é carregada como resultado de uma operação do botão Voltar - é acionado somente quando a página é carregada pela primeira vez.

Alguém pode me indicar algum código de exemplo para vários navegadores (Firefox, Opera, Safari, IE,…) que resolve esse problema? Estou familiarizado com o pageshowevento do Firefox, mas infelizmente nem o Opera nem o Safari implementam isso.

Conta
fonte
6
Isso não é um problema - ele permite que a página da Web seja carregada rapidamente quando o usuário pressiona o botão Voltar. Veja minha resposta abaixo para obter detalhes. As soluções alternativas sugeridas aqui tornam a página da Web mais irritante para o usuário, pois a navegação para trás / para frente é mais lenta.
Nickolay
2
@romkyns: seu comentário não está relacionado a esta pergunta. Quando os navegadores não restauram o estado JS / DOM, eles disparam o evento load.
Nickolay
iOS 5+ botão história que remonta resolvido aqui stackoverflow.com/a/12652160/1090395
Mladen Janjetovic

Respostas:

117

Pessoal, descobri que o JQuery tem apenas um efeito: a página é recarregada quando o botão Voltar é pressionado. Isso não tem nada a ver com " pronto ".

Como é que isso funciona? Bem, o JQuery adiciona um ouvinte de evento onunload .

// http://code.jquery.com/jquery-latest.js
jQuery(window).bind("unload", function() { // ...

Por padrão, ele não faz nada. Mas de alguma forma isso parece desencadear uma recarga no Safari, Opera e Mozilla - não importa o que o manipulador de eventos contenha.

[ edit (Nickolay) : eis por que funciona dessa maneira: webkit.org , developer.mozilla.org . Leia esses artigos (ou meu resumo em uma resposta separada abaixo) e considere se você realmente precisa fazer isso e tornar sua página mais lenta para os usuários.]

Não pode acreditar? Tente o seguinte:

<body onunload=""><!-- This does the trick -->
<script type="text/javascript">
    alert('first load / reload');
    window.onload = function(){alert('onload')};
</script>
<a href="http://stackoverflow.com">click me, then press the back button</a>
</body>

Você verá resultados semelhantes ao usar o JQuery.

Você pode comparar com este sem onunload

<body><!-- Will not reload on back button -->
<script type="text/javascript">
    alert('first load / reload');
    window.onload = function(){alert('onload')};
</script>
<a href="http://stackoverflow.com">click me, then press the back button</a>
</body>
user123444555621
fonte
1
Muito bom .. embora esse seja um recurso / bug não documentado e possa simplesmente parar de funcionar em versões futuras do navegador, mas ainda é interessante.
Wadih M.
3
Isso também funciona (não esqueça a parte onunload = "", caso contrário não funcionará no ff3): <body onload = "alert ('onload');" onunload = "">
Wadih M.
3
Isso ocorre porque o navegador assume que a página não pode ser acessada se tiver um onunloadmanipulador (a página já destruiu tudo; por que armazená-la em cache?).
Casey Chu
14
A resposta parece não funcionar em navegadores modernos - verificada mais recente no Chrome e Opera
Andrew
10
ele não funciona no iPad safari ... por favor, desmarcar isso como uma resposta
xus
74

Alguns navegadores modernos (Firefox, Safari e Opera, mas não o Chrome) suportam o cache "back / forward" especial (vou chamá-lo de bfcache, que é um termo inventado pela Mozilla), envolvido quando o usuário navega em Voltar. Ao contrário do cache normal (HTTP), ele captura o estado completo da página (incluindo o estado de JS, DOM). Isso permite recarregar a página mais rapidamente e exatamente como o usuário a deixou.

O loadevento não deve ser acionado quando a página é carregada deste bfcache. Por exemplo, se você criou sua interface do usuário no manipulador "load" e o evento "load" foi acionado uma vez no carregamento inicial e na segunda vez em que a página foi recarregada a partir do bfcache, a página terminaria com duplicar elementos da interface do usuário.

É também por isso que adicionar o manipulador "descarregar" impede que a página seja armazenada no bfcache (tornando mais lento a navegação de volta para) - o manipulador descarregar pode executar tarefas de limpeza, o que pode deixar a página em estado impraticável.

Para páginas que precisam saber quando estão sendo navegadas / retornadas, Firefox 1.5+ e a versão do Safari com a correção do bug 28758 oferecem suporte a eventos especiais chamados "pageshow" e "pagehide".

Referências:

Nickolay
fonte
Isso é muito legal. Atualmente, estou em uma situação em que minhas manipulações domésticas não parecem ser salvas no bfcache. Existem situações em que você pode esperar isso?
Benson
1
@Benson: os possíveis motivos para o Firefox não salvar sua página no bfcache estão listados na página dev.mo à qual vinculei. Eu não acho que é possível ter a página salva no bfcache, mas determinado estado do DOM não será salvo.
Nickolay
Nickolay, sinto sua relutância em forçar uma recarga e desfazer o bom trabalho feito pelo bfcache, mas existe outra maneira de atualizar o domínio da página no bfcache? Por exemplo, considere a situação em que vou de uma página que possui uma lista de mensagens para uma delas e, quando voltar ", quero que o indicador de leitura / não lida seja alterado. Como isso pode ser feito sem recarregar a página?
Greg
@ Greg: você quer dizer como desenvolvedor controlando a página? Dispare uma solicitação ajax de um ouvinte de 'pageshow'.
Nickolay
Alguma idéia de como usar o jQuery E obter suporte rápido ao bfcache?
Alex Black
31

Encontrei um problema que meu js não estava executando quando o usuário clicou para trás ou para frente. Primeiro, decidi parar o cache do navegador, mas esse não parecia ser o problema. Meu javascript foi definido para ser executado depois que todas as bibliotecas etc. foram carregadas. Eu verifiquei isso com o evento readyStateChange.

Após alguns testes, descobri que o readyState de um elemento em uma página em que foi clicada em voltar não é 'carregado', mas 'completo'. Adicionando|| element.readyState == 'complete' à minha declaração condicional resolveu meus problemas.

Apenas pensei em compartilhar minhas descobertas, espero que elas ajudem alguém.

Editar para completar

Meu código tinha a seguinte aparência:

script.onreadystatechange(function(){ 
   if(script.readyState == 'loaded' || script.readyState == 'complete') {
      // call code to execute here.
   } 
});

No exemplo de código acima, a variável de script estava um elemento de script recém-criado que foi adicionado ao DOM.

Brian Heese
fonte
7
Onde você adicionou isso? E como você conseguiu acionar algo depois que o usuário reagiu? Por favor, mostre-nos algum código!
Keerigan
O que você quer dizer quando diz "minha declaração condicional"?
precisa saber é o seguinte
1
@Phillip Uma declaração condicional é uma declaração if.
Brian Heese
22

OK, aqui está uma solução final baseada na solução inicial do ckramer e no exemplo do palehorse que funciona em todos os navegadores, incluindo o Opera. Se você definir history.navigationMode como 'compatible', a função ready do jQuery será acionada nas operações do botão Voltar no Opera, bem como nos outros principais navegadores.

Esta página tem mais informações .

Exemplo:

history.navigationMode = 'compatible';
$(document).ready(function(){
  alert('test');
});

Eu testei isso no Opera 9.5, IE7, FF3 e Safari e funciona em todos eles.

Conta
fonte
2
Obviamente, já faz um tempo (cerca de 5,5 anos), mas vale a pena notar que seu link está morto.
7114 Jeff
2
Esta solução não funciona para mim. Eu tenho esse problema no Firefox mais recente (45.0.1)
Armin
6

Não consegui que os exemplos acima funcionassem. Eu simplesmente queria acionar uma atualização de certas áreas div modificadas ao voltar para a página usando o botão Voltar. O truque que usei foi definir um campo de entrada oculto (chamado de "bit sujo") para 1 assim que as áreas div forem alteradas em relação ao original. O campo de entrada oculto, na verdade, mantém seu valor quando clico em voltar, para que seja possível carregar esse bit. Se estiver definido, atualizo a página (ou apenas atualizo as divs). No carregamento original, no entanto, o bit não está definido, portanto, não perco tempo carregando a página duas vezes.

<input type='hidden' id='dirty'>

<script>
$(document).ready(function() {
  if ($('#dirty').val()) {
    // ... reload the page or specific divs only
  }
  // when something modifies a div that needs to be refreshed, set dirty=1
  $('#dirty').val('1');
});
</script>

E seria acionado corretamente sempre que eu clicasse no botão Voltar.

thorie
fonte
3
Embora isso não funcione no Firefox, acho que é uma maneira engenhosa de lidar com a situação no IE / Chrome, onde a persistência do campo oculto é muito útil. Eu usei seu truque e também o evento "pageshow", por isso abordo todos os principais navegadores.
Magnus Smith
Qual navegador não funciona com a exibição de paginação?
Justin Justin
4

Se bem me lembro, adicionar um evento unload () significa que a página não pode ser armazenada em cache (no cache de avanço / retrocesso) - porque o estado muda / pode mudar quando o usuário navega. Portanto, não é seguro restaurar o estado de último segundo da página ao retornar a ela navegando pelo objeto de histórico.


fonte
4

Eu pensei que isso seria para "onunload", não para carregamento de página, pois não estamos falando de disparar um evento ao pressionar "Back"? $ document.ready () é para eventos desejados no carregamento da página, não importa como você chegue a essa página (por exemplo, redirecionar, abrir o navegador diretamente para o URL etc.), não ao clicar em "Voltar", a menos que você esteja falando sobre o que disparar na página anterior quando carregar novamente. E não tenho certeza de que a página não esteja sendo armazenada em cache, pois descobri que os Javascripts ainda estão, mesmo quando $ document.ready () está incluído neles. Tivemos que pressionar Ctrl + F5 ao editar nossos scripts que possuem esse evento sempre que os revisamos e queremos testar os resultados em nossas páginas.

$(window).unload(function(){ alert('do unload stuff here'); }); 

é o que você deseja para um evento onunload ao pressionar "Voltar" e descarregar a página atual e também dispara quando um usuário fecha a janela do navegador. Isso soou mais como o desejado, mesmo que eu esteja em menor número com as respostas $ document.ready (). Basicamente, a diferença está entre um evento disparado na página atual enquanto está sendo fechado ou aquele carregado ao clicar em "Voltar" enquanto está sendo carregado. Testado no IE 7, não posso falar pelos outros navegadores, pois eles não são permitidos onde estamos. Mas isso pode ser outra opção.

Tom
fonte
4

Posso confirmar ao ckramer que o evento pronto do jQuery funciona no IE e no FireFox. Aqui está uma amostra:

<html>
<head>
    <title>Test Page</title>
    <script src="http://code.jquery.com/jquery-latest.js" type="text/javascript"></script>
    <script type="text/javascript">
            $(document).ready(function () {
               var d = new Date();
               $('#test').html( "Hi at " + d.toString() );
            });
    </script>
</head>
<body>
    <div id="test"></div>
    <div>
        <a href="http://www.google.com">Go!</a>
    </div>
</body>
</html>
cavalo pálido
fonte
4

para as pessoas que não querem usar a biblioteca jquery inteira, extraí a implementação em código separado. Tem apenas 0,4 KB de tamanho.

Você pode encontrar o código, juntamente com um tutorial em alemão neste wiki: http://www.easy-coding.de/wiki/html-ajax-und-co/onload-event-cross-browser-kompatibler-domcontentloaded.html

Torben Brodt
fonte
1
O link solitário é considerado uma resposta ruim (consulte as perguntas frequentes ), pois não faz sentido por si só e não é garantido que o recurso de destino esteja vivo no futuro . Seria preferível incluir aqui as partes essenciais da resposta e fornecer o link para referência.
J0k
3

O evento pronto do jQuery foi criado para esse tipo de problema. Você pode pesquisar na implementação para ver o que está acontecendo nos bastidores.

ckramer
fonte
6
Muito tempo depois, readyparece não ter sido acionado no Firefox ao usar o botão Voltar. Veja também a resposta de Nickolay .
Arjan
2

Bill, ouso responder à sua pergunta, mas não tenho 100% de certeza com meus palpites. Eu acho que outros navegadores do IE, ao levar o usuário a uma página no histórico, não apenas carregarão a página e seus recursos do cache, mas também restaurarão todo o estado do DOM (sessão de leitura) para ela. O IE não faz a restauração do DOM (ou, no momento da concessão, não) e, portanto, o evento onload parece ser necessário para a reinicialização adequada da página.

Sergey Ilinsky
fonte
2

Tentei a solução de Bill usando $ (document) .ready ... mas no começo não funcionou. Descobri que, se o script for colocado após a seção html, ele não funcionará. Se for a seção principal, funcionará, mas apenas no IE. O script não funciona no Firefox.

Johann
fonte
1

OK, tentei isso e funciona no Firefox 3, Safari 3.1.1 e IE7, mas não no Opera 9.52.
Se você usar o exemplo mostrado abaixo (com base no exemplo de palehorse), receberá uma caixa de alerta quando a página for carregada pela primeira vez. Mas se você for para outro URL e pressionar o botão Voltar para voltar a esta página, não verá uma caixa de alerta no Opera (mas sim nos outros navegadores).

Enfim, acho que isso está perto o suficiente por enquanto. Obrigado a todos!

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Untitled Document</title>
<meta http-equiv="expires" content="0">
<script src="jquery.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready( 
                    function(){
                      alert('test');
                    }
                 );
</script>
</head>
<body>
<h1>Test of the page load event and the Back button using jQuery</h1>
</body>
</html>
Conta
fonte
1

O evento Unload não está funcionando bem no IE 9. Tentei com o evento load (onload ()), está funcionando bem no IE 9 e FF5 .

Exemplo:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript">
    jQuery(window).bind("load", function() {
        $("[name=customerName]").val('');
    });
</script>
</head>
<body>
    <h1>body.jsp</h1>
    <form action="success.jsp">
        <div id="myDiv">

        Your Full Name: <input name="yourName" id="fullName"
            value="Your Full Name" /><br> <br> <input type="submit"><br>

        </div>

    </form>
</body>
</html>
Mallesham
fonte
0

Eu usei um modelo html. No arquivo custom.js deste modelo, havia uma função como esta:

    jQuery(document).ready(function($) {

       $(window).on('load', function() {
          //...
       });

    });

Mas essa função não estava funcionando quando eu voltei depois de ir para outra página.

Então, eu tentei isso e funcionou:

    jQuery(document).ready(function($) {
       //...
    });

   //Window Load Start
   window.addEventListener('load', function() {
       jQuery(document).ready(function($) {
          //...
       });
   });

Agora, eu tenho 2 funções "prontas", mas não dá nenhum erro e a página está funcionando muito bem.

No entanto, tenho que declarar que ele foi testado no Windows 10 - Opera v53 e Edge v42, mas em outros navegadores. Lembre-se disso ...

Nota: a versão do jquery era 3.3.1 e a versão da migração era 3.0.0

bafsar
fonte