Estou usando a API de histórico para meu aplicativo da web e tenho um problema. Eu faço chamadas Ajax para atualizar alguns resultados na página e uso o history.pushState () para atualizar a barra de localização do navegador sem recarregar a página. Então, é claro, eu uso window.popstate para restaurar o estado anterior quando o botão Voltar é clicado.
O problema é bem conhecido - o Chrome e o Firefox tratam esse evento popstate de maneira diferente. Embora o Firefox não inicialize na primeira vez, o Chrome o faz. Eu gostaria de ter o estilo do Firefox e não disparar o evento no carregamento, pois ele apenas atualiza os resultados exatamente com os mesmos no carregamento. Existe uma solução alternativa, exceto usar History.js ? Não estou com vontade de usá-lo - ele precisa de muitas bibliotecas JS sozinho e, como preciso implementá-lo em um CMS com muito JS, gostaria de minimizar o JS que estou colocando nele .
Então, gostaria de saber se existe uma maneira de fazer o Chrome não disparar 'popstate' no carregamento ou, talvez, alguém tentou usar History.js com todas as bibliotecas agrupadas em um arquivo.
Respostas:
Na versão 19 do Google Chrome, a solução de @spliter parou de funcionar. Como @johnnymire apontou, history.state no Chrome 19 existe, mas é nulo.
Minha solução alternativa é adicionar window.history.state! == null para verificar se existe estado em window.history:
Eu testei em todos os principais navegadores e nas versões 19 e 18 do Chrome. Parece que funciona.
fonte
in
enull
verificar apenas,!= null
pois isso também resolveráundefined
.null
em seushistory.pushState()
métodos comohistory.pushState(null,null,'http//example.com/)
. Concedido, isso provavelmente seria a maioria dos usos (é assim que é configurado no jquery.pjax.js e na maioria das outras demos). Mas se os navegadores forem implementadoswindow.history.state
(como FF e Chrome 19+), window.history.state pode ser não nulo em uma atualização ou após a reinicialização do navegadorCaso você não queira tomar medidas especiais para cada gerenciador adicionado ao onpopstate, minha solução pode ser interessante para você. Uma grande vantagem dessa solução é também que os eventos onpopstate podem ser manipulados antes que o carregamento da página seja concluído.
Apenas execute este código uma vez antes de adicionar qualquer manipulador onpopstate e tudo deve funcionar como esperado (também conhecido como no Mozilla ^^) .
Como funciona:
Chrome, Safari e provavelmente outros navegadores de webkit disparam o evento onpopstate quando o documento é carregado. Isso não é intencional, portanto, bloqueamos eventos popstate até o primeiro ciclo de loop de eventos após o documento ter sido carregado. Isso é feito pelas chamadas preventDefault e stopImmediatePropagation (ao contrário de stopPropagation, stopImmediatePropagation interrompe todas as chamadas de manipulador de eventos instantaneamente).No entanto, como o readyState do documento já está em "complete" quando o Chrome dispara onpopstate erroneamente, permitimos eventos opopstate, que foram disparados antes de o carregamento do documento terminar para permitir chamadas onpopstate antes do documento ser carregado.
Atualização 2014-04-23: Corrigido um bug em que os eventos popstate eram bloqueados se o script fosse executado depois que a página fosse carregada.
fonte
window.history.state
falha na recarga se um estado foi definido. A configuração da variável antes do código de desordem pushState. Sua solução é elegante e pode ser descartada em cima de outros scripts, sem afetar o resto da base de código. Obrigado.Usar apenas setTimeout não é uma solução correta porque você não tem ideia de quanto tempo levará para o conteúdo ser carregado, então é possível que o evento popstate seja emitido após o tempo limite.
Aqui está minha solução: https://gist.github.com/3551566
fonte
A solução foi encontrado em jquery.pjax.js linhas 195-225:
fonte
Uma solução mais direta do que reimplementar pjax é definir uma variável em pushState e verificar a variável em popState, para que o popState inicial não seja disparado inconsistentemente no carregamento (não é uma solução específica de jquery, apenas usando-o para eventos):
fonte
window.history.ready
é sempre verdade.!window.history.ready && !ev.originalEvent.state
- essas duas coisas nunca são definidas quando eu atualizo a página. portanto, nenhum código é executado.O evento onpopstate inicial do Webkit não tem estado atribuído, então você pode usar isso para verificar o comportamento indesejado:
Uma solução abrangente, permitindo a navegação de volta à página original, se basearia nesta ideia:
Embora isso ainda possa disparar duas vezes (com alguma navegação bacana), pode ser tratado simplesmente com uma verificação em relação ao href anterior.
fonte
window.history.state
também é nulo no iOS. Basta verificar se a propriedade e.state é nula.Esta é a minha solução alternativa.
fonte
Esta é minha solução:
fonte
A melhor maneira de fazer o Chrome não disparar popstate no carregamento de uma página é votar https://code.google.com/p/chromium/issues/detail?id=63040 . Eles sabem que o Chrome não está em conformidade com as especificações HTML5 há dois anos inteiros e ainda não corrigiu isso!
fonte
Em caso de uso,
event.state !== null
retornar ao histórico para a primeira página carregada não funcionará em navegadores não móveis. Eu uso sessionStorage para marcar quando a navegação ajax realmente começa.fonte
As soluções apresentadas apresentam um problema no recarregamento da página. O seguinte parece funcionar melhor, mas eu só testei o Firefox e o Chrome. Ele usa a realidade, que parece haver uma diferença entre
e.event.state
ewindow.history.state
.fonte
e.event
is undefinedEu sei que você pediu contra isso, mas você realmente deveria apenas usar History.js, pois ele limpa um milhão de incompatibilidades do navegador. Eu segui a rota de conserto manual apenas para descobrir mais tarde que havia mais e mais problemas que você só descobrirá no futuro. Realmente não é tão difícil hoje em dia:
E leia a api em https://github.com/browserstate/history.js
fonte
Isso resolveu o problema para mim. Tudo o que fiz foi definir uma função de tempo limite que atrasa a execução da função por tempo suficiente para perder o evento popstate que é disparado no pageload
fonte
Você pode criar um evento e dispará-lo após o manipulador onload.
Note, isso está um pouco quebrado no Chrome / Safari, mas eu enviei o patch para o WebKit e ele deve estar disponível em breve, mas é a forma "mais correta".
fonte
Isso funcionou para mim no Firefox e Chrome
fonte