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.

MilMike
fonte
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
1
[Hasher] github.com/millermedeiros/hasher
Vishnoo Rath 15/01/15
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 .

meandmycode
fonte
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
Milhas
fonte
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/

Khan Salahuddin
fonte
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.

Sergio Cinos
fonte
11

Ben Alman tem um ótimo plugin jQuery para lidar com isso: http://benalman.com/projects/jquery-hashchange-plugin/

Se você não estiver usando o jQuery, pode ser uma referência interessante para dissecar.

CJ.
fonte
O plugin Ben Alman parece não ser mais mantido. Há uma série de garfos embora.
Mnebuerquo
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.

gion_13
fonte
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.

Sprose
fonte
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.

Sergey Ilinsky
fonte
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 !

Balupton
fonte
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.

homem Morcego
fonte
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

Tom
fonte
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.

moha297
fonte