Como detectar a mudança de URL no JavaScript

Como posso verificar se um URL foi alterado em JavaScript? Por exemplo, sites como o GitHub, que usam AJAX, appendão informações da página após um símbolo # para criar uma URL exclusiva sem recarregar a página. Qual é a melhor maneira de detectar se esse URL muda?

  • O evento onload chamado novamente?
  • Existe um manipulador de events para o URL?
  • Ou o URL deve ser verificado a cada segundo para detectar uma alteração?

Nos navegadores modernos (IE8 +, FF3.6 +, Chrome), você pode simplesmente ouvir o evento hashchange na window .

Em alguns navegadores antigos, você precisa de um timer que verifique continuamente location.hash . Se você estiver usando o jQuery, existe um plugin que faz exatamente isso.

Com jquery (e um plug-in) você pode fazer

 $(window).bind('hashchange', function() { /* things */ }); 

http://benalman.com/projects/jquery-hashchange-plugin/

Caso contrário, sim, você teria que usar setInterval e verificar uma alteração no evento de hash (window.location.hash)

Atualizar! Um rascunho simples

 function hashHandler(){ this.oldHash = window.location.hash; this.Check; var that = this; var detect = function(){ if(that.oldHash!=window.location.hash){ alert("HASH CHANGED - new has" + window.location.hash); that.oldHash = window.location.hash; } }; this.Check = setInterval(function(){ detect() }, 100); } var hashDetection = new hashHandler(); 

use este código

 window.onhashchange = function() { //code } 

com jQuery

 $(window).bind('hashchange', function() { //code }); 

EDIT depois de um pouco de pesquisa:

De alguma forma, parece que fui enganado pela documentação presente nos documentos do Mozilla. O evento popstate (e sua function de retorno de chamada onpopstate ) não são acionados sempre que o pushState() ou replaceState() são chamados no código. Portanto, a resposta original não se aplica em todos os casos.

No entanto, há uma maneira de contornar isso através da correção das funções de acordo com @ alpha123 :

 var pushState = history.pushState; history.pushState = function () { pushState.apply(history, arguments); fireEvents('pushState', arguments); // Some event-handling function }; 

Resposta original

Dado que o título desta pergunta é ” Como detectar a mudança de URL “, a resposta, quando você quer saber quando o caminho completo muda (e não apenas a âncora de hash), é que você pode ouvir o evento popstate :

 window.onpopstate = function(event) { console.log("location: " + document.location + ", state: " + JSON.stringify(event.state)); }; 

Referência para popstate no Mozilla Docs

Atualmente (jan 2017) há suporte para popstate de 92% dos navegadores em todo o mundo.

Adicione um ouvinte de evento de alteração de hash!

 window.addEventListener('hashchange', function(e){console.log('hash changed')}); 

Ou para ouvir todas as alterações de URL:

 window.addEventListener('popstate', function(e){console.log('url changed')}); 

Isso é melhor do que algo como o código abaixo porque só existe uma coisa no window.onhashchange e você provavelmente estará sobrescrevendo o código de outra pessoa.

 // Bad code example window.onhashchange = function() { // Code that overwrites whatever was previously in window.onhashchange } 

essa solução funcionou para mim:

 var oldURL = ""; var currentURL = window.location.href; function checkURLchange(currentURL){ if(currentURL != oldURL){ alert("url changed!"); oldURL = currentURL; } oldURL = window.location.href; setInterval(function() { checkURLchange(window.location.href); }, 1000); } checkURLchange(); 

Embora seja uma pergunta antiga, o projeto Barra de localização é muito útil.

 var LocationBar = require("location-bar"); var locationBar = new LocationBar(); // listen to all changes to the location bar locationBar.onChange(function (path) { console.log("the current url is", path); }); // listen to a specific change to location bar // eg Backbone builds on top of this method to implement // it's simple parametrized Backbone.Router locationBar.route(/some\-regex/, function () { // only called when the current url matches the regex }); locationBar.start({ pushState: true }); // update the address bar and add a new entry in browsers history locationBar.update("/some/url?param=123"); // update the address bar but don't add the entry in history locationBar.update("/some/url", {replace: true}); // update the address bar and call the `change` callback locationBar.update("/some/url", {trigger: true}); 

Para ouvir as alterações de URL, veja abaixo:

 window.onpopstate = function(event) { console.log("location: " + document.location + ", state: " + JSON.stringify(event.state)); }; 

Use este estilo se você pretende interromper / remover o ouvinte após uma determinada condição.

 window.addEventListener('popstate', function(e) { console.log('url changed') }); 

Veja a function de descarregamento do jQuery. Ele lida com todas as coisas.

https://api.jquery.com/unload/

O evento unload é enviado para o elemento window quando o usuário navega para fora da página. Isso pode significar uma de muitas coisas. O usuário poderia ter clicado em um link para sair da página ou digitar um novo URL na barra de endereço. Os botões para frente e para trás acionarão o evento. Fechar a janela do navegador fará com que o evento seja acionado. Até mesmo um recarregamento de página primeiro criará um evento de descarregamento.

 $(window).unload( function(event) { alert("navigating"); } ); 
 window.addEventListener("beforeunload", function (e) { // do something }, false); 

Você está iniciando um novo setInterval em cada chamada, sem cancelar o anterior – provavelmente você só pretendia ter um setTimeout

Ao fazer uma pequena extensão do Chrome, enfrentei o mesmo problema com um problema adicional: às vezes, a página muda, mas não a URL.

Por exemplo, basta ir para a página inicial do Facebook e clicar no botão ‘Home’. Você recarregará a página, mas o URL não será alterado (estilo de aplicativo de uma página).

99% do tempo, estamos desenvolvendo sites para que possamos obter esses events de Frameworks como Angular, React, Vue etc.

MAS , no meu caso de uma extensão do Chrome (no Vanilla JS), eu tive que ouvir um evento que será acionado para cada “mudança de página”, que geralmente pode ser capturada pelo URL alterado, mas às vezes isso não acontece.

Minha solução caseira foi a seguinte:

 listen(window.history.length); var oldLength = -1; function listen(currentLength) { if (currentLength != oldLength) { // Do your stuff here } oldLength = window.history.length; setInterval(function () { listen(window.history.length); }, 1000); } 

Então, basicamente, a solução leoneckert, aplicada ao histórico da janela, que mudará quando uma página for alterada em um aplicativo de página única.

Não é ciência de foguetes, mas solução mais limpa que eu encontrei, considerando que estamos verificando apenas uma igualdade inteira aqui, e não objects maiores ou o DOM inteiro.