Portanto, agora que o HTML5 se propõe history.pushState
a alterar o histórico dos navegadores, os sites começam a usá-lo em combinação com o Ajax, em vez de alterar o identificador de fragmento da URL.
Infelizmente, isso significa que essas chamadas não podem mais ser detectadas onhashchange
.
Minha pergunta é: Existe uma maneira confiável (hack?;)) De detectar quando um site é usado history.pushState
? A especificação não declara nada sobre eventos gerados (pelo menos, não consegui encontrar nada).
Tentei criar uma fachada e substituí-lo window.history
por meu próprio objeto JavaScript, mas não teve nenhum efeito.
Mais explicações: estou desenvolvendo um complemento do Firefox que precisa detectar essas alterações e agir de acordo.
Sei que havia uma pergunta semelhante, há alguns dias, que perguntava se a escuta de alguns eventos do DOM seria eficiente, mas prefiro não confiar nisso, porque esses eventos podem ser gerados por várias razões diferentes.
Atualizar:
Aqui está um jsfiddle (use o Firefox 4 ou Chrome 8) que mostra que onpopstate
não é acionado quando pushState
é chamado (ou estou fazendo algo errado? Fique à vontade para aprimorá-lo!).
Atualização 2:
Outro problema (lateral) é que window.location
não é atualizado ao usar pushState
(mas eu li sobre isso já aqui no SO, eu acho).
fonte
history
objeto inteiro . Isso pode ser desnecessário neste caso.window.history
é somente leitura, mas as propriedades do objeto a história não é ... Muito obrigada por esta solução :)pushState
método nativo para uso posterior. Então, ao invés de uma variável global que eu escolhi para encapsular todo o código em um IIFE: en.wikipedia.org/wiki/Immediately-invoked_function_expressionEu costumava usar isso:
É quase o mesmo que os galambalazs fizeram.
Geralmente é um exagero. E pode não funcionar em todos os navegadores. (Só me preocupo com a minha versão do meu navegador.)
(E deixa um var
_wr
, então você pode querer envolvê-lo ou algo assim. Eu não me importo com isso.)fonte
Finalmente encontrei a maneira "correta" de fazer isso! Requer adicionar um privilégio à sua extensão e usar a página de plano de fundo (não apenas um script de conteúdo), mas funciona.
O evento que você deseja é
browser.webNavigation.onHistoryStateUpdated
disparado quando uma página usa ahistory
API para alterar o URL. Ele é acionado apenas nos sites aos quais você tem permissão para acessar e também pode usar um filtro de URL para reduzir ainda mais o spam, se necessário. Requer awebNavigation
permissão (e, claro, a permissão de host para os domínios relevantes).O retorno de chamada do evento obtém o ID da guia, o URL que está sendo "navegado" e outros detalhes. Se você precisar executar uma ação no script de conteúdo dessa página quando o evento for disparado, injete o script relevante diretamente da página de plano de fundo ou faça com que o script de conteúdo abra
port
a página de plano de fundo quando ela for carregada, salve a página de plano de fundo essa porta em uma coleção indexada pelo ID da guia e envia uma mensagem pela porta relevante (do script em segundo plano para o script de conteúdo) quando o evento é acionado.fonte
Você poderia se associar ao
window.onpopstate
evento?https://developer.mozilla.org/en/DOM%3awindow.onpopstate
Dos documentos:
fonte
history.go
,.back
) funções são chamadas. Mas não por diantepushState
. Aqui está minha tentativa de testá-lo, talvez eu faça algo errado: jsfiddle.net/fkling/vV9vd Parece apenas relacionado dessa maneira que, se o histórico foi alteradopushState
, o objeto de estado correspondente é passado para o manipulador de eventos quando os outros métodos são chamados.Como você está perguntando sobre um complemento do Firefox, eis o código que eu comecei a trabalhar. O uso não
unsafeWindow
é mais recomendado e ocorre um erro quando o pushState é chamado a partir de um script do cliente após ser modificado:Em vez disso, há uma API chamada exportFunction que permite que a função seja injetada da
window.history
seguinte maneira:fonte
unsafeWindow.history,
parawindow.history
. Não estava funcionando para mim com o Windows inseguro.A resposta de galambalazs é o remendo do macaco
window.history.pushState
ewindow.history.replaceState
, por algum motivo, ele parou de funcionar para mim. Aqui está uma alternativa que não é tão boa porque usa a pesquisa:fonte
Eu acho que esse tópico precisa de uma solução mais moderna.
Tenho certeza que
nsIWebProgressListener
estava por aí, então estou surpreso que ninguém tenha mencionado.De um framescript (para compatibilidade com e10s):
Então ouvindo no
onLoacationChange
Aparentemente, isso pegará todos os pushState's. Mas há um comentário avisando que "TAMBÉM dispara para pushState". Portanto, precisamos fazer mais algumas filtragem aqui para garantir que sejam apenas coisas do passado.
Baseado em: https://github.com/jgraham/gecko/blob/55d8d9aa7311386ee2dabfccb481684c8920a527/toolkit/modules/addons/WebNavigation.jsm#L18
E: resource: //gre/modules/WebNavigationContent.js
fonte
Bem, eu vejo muitos exemplos de substituição da
pushState
propriedade,history
mas não tenho certeza de que seja uma boa ideia. Prefiro criar um evento de serviço com uma API semelhante ao histórico, para que você possa controlar não apenas o estado push, mas também o estado e também abre portas para muitas outras implementações que não dependem da API de histórico global. Por favor, verifique o seguinte exemplo:Se você precisar da
EventEmitter
definição, o código acima será baseado no emissor do evento NodeJS: https://github.com/nodejs/node/blob/36732084db9d0ff59b6ce31e839450cd91a156be/lib/events.js .utils.inherits
A implementação pode ser encontrada aqui: https://github.com/nodejs/node/blob/36732084db9d0ff59b6ce31e839450cd91a156be/lib/util.js#L970fonte
Prefiro não sobrescrever o método de histórico nativo, portanto, essa implementação simples cria minha própria função chamada eventedPush state, que apenas envia um evento e retorna history.pushState (). De qualquer maneira, funciona bem, mas acho essa implementação um pouco mais limpa, pois os métodos nativos continuarão a funcionar como os desenvolvedores futuros esperam.
fonte
Com base na solução fornecida por @gblazex , caso você queira seguir a mesma abordagem, mas usando as funções de seta, siga o exemplo abaixo em sua lógica javascript:
Em seguida, implemente outra função
_notifyUrl(url)
que aciona qualquer ação necessária que você possa precisar quando o URL da página atual for atualizado (mesmo que a página ainda não tenha sido carregada)fonte
Como eu só queria a nova URL, adaptei os códigos de @gblazex e @Alberto S. para obter isso:
fonte
Não acho que seja uma boa ideia modificar funções nativas, mesmo que você possa, e você deve sempre manter o escopo do aplicativo, para que uma boa abordagem não seja usar a função pushState global; em vez disso, use uma de sua preferência:
Observe que, se qualquer outro código usar a função pushState nativa, você não obterá um gatilho de evento (mas, se isso acontecer, verifique seu código)
fonte
Como estados padrão:
precisamos chamar history.back () para transformar WindowEventHandlers.onpopstate
Então, insted de:
Faz:
fonte