On - window.location.hash - Alterar?


558

Estou usando o Ajax e o hash para navegação.

Existe uma maneira de verificar se o window.location.hashmudou assim?

http://example.com/blah # 123 a http://example.com/blah # 456

Funciona se eu verificar quando o documento for carregado.

Mas se eu tiver a navegação com #hash, ela não funcionará quando pressiono o botão Voltar no navegador (então pulo de blá # 456 para blá # 123).

Ele aparece dentro da caixa de endereço, mas não consigo pegá-lo com JavaScript.


6
Faça o checkout deste plugin jquery: github.com/cowboy/jquery-hashchange
Xavi

9
O History.js suporta a funcionalidade de gerenciamento de estado HTML5 (para que você não precise mais usar hashes!) E o degrada normalmente para navegadores HTML4 usando alterações de hash. Ele suporta jQuery, MooTools e Prototype prontos para uso.
precisa saber é o seguinte

@balupton, Na verdade, ainda precisamos usar hashes para fornecer feedback ao usuário de que uma "nova página" foi inserida em seu histórico, a menos que você use a alteração de URL como feedback.
Pacerier


hmm ... Eu acho que você precisa
moar

Respostas:


617

A única maneira de realmente fazer isso (e é como a 'história realmente simples' faz isso) é definindo um intervalo que continua verificando o hash atual e comparando-o com o que era antes, fazemos isso e permitimos que os assinantes assinem uma alteração evento que disparamos se o hash mudar .. não é perfeito, mas os navegadores realmente não suportam esse evento nativamente.


Atualize para manter esta resposta atualizada:

Se você estiver usando o jQuery (que hoje deve ser um pouco fundamental para a maioria), uma boa solução é usar a abstração que o jQuery fornecer, usando seu sistema de eventos para ouvir eventos de alteração de hash no objeto da janela.

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

O bom aqui é que você pode escrever um código que nem precisa se preocupar com o suporte à mudança de hash, no entanto, você precisa fazer alguma mágica, na forma de um recurso jQuery um pouco menos conhecido, eventos especiais do jQuery .

Com esse recurso, você basicamente executa algum código de configuração para qualquer evento, a primeira vez que alguém tenta usar o evento de qualquer maneira (como vincular ao evento).

Nesse código de configuração, você pode verificar o suporte nativo ao navegador e, se o navegador não implementar isso nativamente, você pode configurar um cronômetro único para pesquisar alterações e acionar o evento jQuery.

Isso desvincula completamente seu código da necessidade de entender esse problema de suporte; a implementação de um evento especial desse tipo é trivial (para obter uma versão funcional simples de 98%), mas por que fazer isso quando outra pessoa já o fez .


7
IE8 faz. Mais por vir
Sergey Ilinsky

28
A versão mais recente do Firefox (3.6 alfa) agora também suporta o evento de alteração de hash nativo: developer.mozilla.org/en/DOM/window.onhashchange Certamente vale a pena fazer uma verificação para este evento, mas observe que o IE8 informará o evento existe quando está sendo executado no modo compatível com o IE7 .. infelizmente o evento não é acionado .. você precisa verificar o evento e se o navegador não parece ser o IE7 .. suspiro (ou tentar acionar o evento com o método fireEvent do IE).
meandmycode

8
No momento da escrita, o WebKit também dispara o hashchangeevento, enquanto o Safari (estável) ainda não.
Jholster

51
Só para acrescentar mais uma atualização, o hashchangeevento é agora amplamente suportado: caniuse.com/#search=hash
Paystey

19
Eu sou o único que pensa que respostas não solicitadas do jQuery são uma dor?
Luc

290

HTML5 especifica um hashchangeevento . Agora, este evento é suportado por todos os navegadores modernos . Foi adicionado suporte nas seguintes versões do navegador:

  • Internet Explorer 8
  • Firefox 3.6
  • Chrome 5
  • Safari 5
  • Opera 10.6

20
Atualização: FF 5, Safari 5 e Chrome 12 suportam este evento a partir de junho de 2011.
james.garriss

2
Aqui está a página CanIUse para hashchange . Aqui está hashchange no modo quirks . O suporte do IE é incorreto no que diz respeito à distinção entre maiúsculas e minúsculas.
Tobu

3
@ todo mundo, não é necessário continuar anexando a resposta na seção de comentários - é para isso que serve o botão "Editar". :)
Michael Martin-Smucker

15
uso:window.onhashchange = function() { doYourStuff(); }
Chris

4
Documentação MDN do evento hashchange .
Dabowheel

52

Observe que, no caso do Internet Explorer 7 e Internet Explorer 9, a ifdeclaração será verdadeira (para "onhashchange" no Windows), mas window.onhashchangenunca será acionada; portanto, é melhor armazenar o hash e verificá-lo após cada 100 milissegundos, independentemente de ter sido alterado ou não. para todas as versões do Internet Explorer.

    if (("onhashchange" in window) && !($.browser.msie)) {
         window.onhashchange = function () {
              alert(window.location.hash);
         }
         // Or $(window).bind( 'hashchange',function(e) {
         //       alert(window.location.hash);
         //   });
    }
    else {
        var prevHash = window.location.hash;
        window.setInterval(function () {
           if (window.location.hash != prevHash) {
              prevHash = window.location.hash;
              alert(window.location.hash);
           }
        }, 100);
    }

EDIT - Desde jQuery 1.9, $.browser.msienão é suportado. Fonte: http://api.jquery.com/jquery.browser/


14

Existem muitos truques para lidar com o History e o window.location.hash nos navegadores IE:

  • Como disse a pergunta original, se você passa da página a.html # b para a.html # c e pressiona o botão Voltar, o navegador não sabe que a página foi alterada. Deixe-me dizer um exemplo: window.location.href será 'a.html # c', não importa se você está em a.html # b ou a.html # c.

  • Na verdade, a.html # be a.html # c são armazenados no histórico apenas se os elementos '<a name="#b">' e '<a name="#c">' existirem anteriormente na página.

  • No entanto, se você colocar um iframe em uma página, navegue de a.html # b para a.html # c nesse iframe e pressione o botão voltar, iframe.contentWindow.document.location.href será alterado conforme o esperado.

  • Se você usar 'document.domain = something ' no seu código, não poderá acessar iframe.contentWindow.document.open () '(e muitos gerenciadores de história fazem isso)

Sei que essa não é uma resposta real, mas talvez as anotações do IE-History sejam úteis para alguém.




9

Você pode implementar facilmente um observador (o método "watch") na propriedade "hash" do objeto "window.location".

O Firefox tem sua própria implementação para observar alterações de objeto , mas se você usar alguma outra implementação (como Observar alterações nas propriedades do objeto em JavaScript ) - para outros navegadores, isso fará o truque.

O código ficará assim:

window.location.watch(
    'hash',
    function(id,oldVal,newVal){
        console.log("the window's hash value has changed from "+oldval+" to "+newVal);
    }
);

Então você pode testá-lo:

var myHashLink = "home";
window.location = window.location + "#" + myHashLink;

E é claro que isso ativará sua função de observador.


Melhor uso: window.location.href em vez de window.location.
Codebeat

3
Ele está assistindo window.location.hash, não window.location.
indefinido

1
@BrianMortenson: de acordo com os documentos ( developer.mozilla.org/en-US/docs/JavaScript/Reference/… ), você deve aplicar watchao objeto que possui a propriedade que está sendo alterada e deseja observá-lo.
gion_13

@ gion_13 Sim, é exatamente isso que eu estava tentando apontar. Por 'He', eu quis dizer você, e foi direcionado ao comentário de Erwinus. Eu deveria ter sido mais claro. Obrigado pelo seu comentário esclarecedor.
indefinido

7

Eu estava usando isso em um aplicativo de reação para fazer a URL exibir parâmetros diferentes, dependendo da exibição do usuário.

Eu assisti o parâmetro hash usando

window.addEventListener('hashchange', doSomethingWithChangeFunction());

Então

doSomethingWithChangeFunction () { 
    // Get new hash value
    let urlParam = window.location.hash;
    // Do something with new hash value
};

Trabalhou um tratamento, trabalha com os botões de avançar e voltar do navegador e também no histórico do navegador.


1
na sua addEventListenerchamada, você deve remover o arquivo ()dedoSomethingWithChangeFunction
Jason S

Você pode fornecer um motivo para remover o ()? Eu sei que ele funcionará com qualquer um deles, e menos código é a melhor opção, mas isso parece exigente, a menos que haja uma razão substancial para fazer isso.
Sprose

6
? não deve funcionar (). A addEventListenerfunção requer que você passe uma função. doSomethingWithChangeFunctioné uma função. doSomethingWithChangeFunction()é o valor de retorno dessa função, que neste caso não é uma função.
Jason S

6

Uma implementação decente pode ser encontrada em http://code.google.com/p/reallysimplehistory/ . O único (mas também) problema e bug que ele possui é: no Internet Explorer, a modificação manual do hash do local redefinirá toda a pilha de histórico (esse é um problema do navegador e não pode ser resolvido).

Observe que o Internet Explorer 8 tem suporte para o evento "hashchange" e, como ele se torna parte do HTML5, você pode esperar que outros navegadores os atualizem.


1

Outra ótima implementação é o jQuery History, que usará o evento onhashchange nativo se for suportado pelo navegador; caso contrário, usará um iframe ou intervalo apropriado para o navegador para garantir que toda a funcionalidade esperada seja emulada com êxito. Ele também fornece uma interface agradável para vincular a determinados estados.

Outro projeto digno de nota também é o jQuery Ajaxy, que é praticamente uma extensão do jQuery History para adicionar ajax ao mix. Como quando você começa a usar ajax com hashes, fica muito complicado !


1
var page_url = 'http://www.yoursite.com/'; // full path leading up to hash;
var current_url_w_hash = page_url + window.location.hash; // now you might have something like: http://www.yoursite.com/#123

function TrackHash() {
    if (document.location != page_url + current_url_w_hash) {
        window.location = document.location;
    }
    return false;
}
var RunTabs = setInterval(TrackHash, 200);

É isso aí ... agora, sempre que você pressionar os botões voltar ou avançar, a página será recarregada conforme o novo valor de hash.


não use cadeias de avaliação
Vitim.us

1

Eu tenho usado path.js para o meu roteamento do lado do cliente. Descobri que é bastante sucinto e leve (também foi publicado no NPM também) e faz uso da navegação baseada em hash.

path.js NPM

path.js GitHub


0

Eu usei um plugin do jQuery, o HUtil , e escrevi uma interface do tipo YUI History sobre ela.

Confira uma vez. Se você precisar de ajuda, eu posso ajudar.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.