On - window.location.hash - Cambia?


558

Sto usando Ajax e hash per la navigazione.

C'è un modo per verificare se il window.location.hash cambiato in questo modo?

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

Funziona se lo controllo quando viene caricato il documento.

Ma se ho una navigazione basata su #hash non funziona quando premo il pulsante indietro sul browser (quindi salto da blah # 456 a blah # 123).

Viene visualizzato nella casella dell'indirizzo, ma non riesco a catturarlo con JavaScript.


6
Dai un'occhiata a questo plugin jquery: github.com/cowboy/jquery-hashchange
Xavi

9
History.js supporta la funzionalità di gestione dello stato HTML5 (quindi non è più necessario utilizzare gli hash!) E lo degrada con garbo nei browser HTML4 utilizzando gli hashchanges. Supporta jQuery, MooTools e Prototype immediatamente.
Balupton,

@balupton, In realtà abbiamo ancora bisogno di usare gli hash per fornire feedback all'utente che una "nuova pagina" è stata inserita nella sua cronologia, a meno che tu non usi la modifica degli URL come feedback.
Pacerier,


hmm ... penso che tu abbia bisogno di moar jQuery
RaisingAgent

Risposte:


617

L'unico modo per farlo davvero (ed è così che la 'realsemplice storia' lo fa), è impostare un intervallo che continui a controllare l'hash corrente e confrontarlo con quello che era prima, lo facciamo e permettiamo agli abbonati di iscriversi a un cambiamento l'evento che generiamo se l'hash cambia ... non è perfetto ma i browser non supportano questo evento in modo nativo.


Aggiorna per mantenere fresca questa risposta:

Se stai usando jQuery (che oggi dovrebbe essere in qualche modo fondamentale per la maggior parte) allora una buona soluzione è usare l'astrazione che ti dà jQuery usando il suo sistema di eventi per ascoltare gli eventi di hashchange sull'oggetto finestra.

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

La cosa bella qui è che puoi scrivere codice che non deve nemmeno preoccuparsi del supporto di hashchange, tuttavia devi fare un po 'di magia, sotto forma di una funzione jQuery un po' meno nota eventi speciali jQuery .

Con questa funzione si ottiene essenzialmente l'esecuzione di un codice di installazione per qualsiasi evento, la prima volta che qualcuno tenta di utilizzare l'evento in qualsiasi modo (come l'associazione all'evento).

In questo codice di configurazione è possibile verificare il supporto del browser nativo e se il browser non lo implementa in modo nativo, è possibile impostare un singolo timer per eseguire il polling per le modifiche e attivare l'evento jQuery.

Questo libera completamente il codice dalla necessità di comprendere questo problema di supporto, l'implementazione di un evento speciale di questo tipo è banale (per ottenere una versione funzionante al 98%), ma perché farlo quando qualcun altro lo ha già fatto .


7
IE8 lo fa. Altro a venire
Sergey Ilinsky,

28
L'ultima build di Firefox (3.6 alpha) ora supporta anche l'evento di modifica dell'hash nativo: developer.mozilla.org/en/DOM/window.onhashchange Vale sicuramente la pena fare un controllo per questo evento, ma nota che IE8 ti dirà l'evento esiste quando è in esecuzione in modalità compatibilità IE7 .. purtroppo l'evento non si attiva .. dovrai controllare l'evento e che il browser non sembra essere IE7 .. sigh (o tentare di attivare l'evento con il metodo fireEvent di IE).
meandmycode,

8
Al momento in cui scrivo, WebKit genera anche un hashchangeevento, mentre Safari (stabile) non lo ha ancora fatto.
jholster,

51
Solo per aggiungere un altro aggiornamento, l' hashchangeevento è ora ampiamente supportato: caniuse.com/#search=hash
Paystey

19
Sono l'unico che pensa che le risposte jQuery indesiderate siano dolorose?
Luc,

290

HTML5 specifica un hashchangeevento . Questo evento è ora supportato da tutti i browser moderni . Il supporto è stato aggiunto nelle seguenti versioni del browser:

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

20
Aggiornamento: FF 5, Safari 5 e Chrome 12 supportano questo evento a partire da giugno 2011.
james.garriss,

2
Ecco la pagina CanIUse per hashchange . Ecco hashchange su quirksmode . Il supporto IE è difettoso rispetto alla distinzione tra maiuscole e minuscole.
Tobu,

3
@Ogni persona, non c'è bisogno di continuare ad aggiungere la risposta nella sezione commenti: ecco a cosa serve il pulsante "Modifica". :)
Michael Martin-Smucker,

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

4
Documentazione MDN dell'evento hashchange .
Dabowheel,

52

Si noti che nel caso di Internet Explorer 7 e Internet Explorer 9 la ifdichiarazione darà true (per "onhashchange" in Windows), ma window.onhashchangenon si attiverà mai, quindi è meglio archiviare l'hash e controllarlo ogni 100 millisecondi se è cambiato o no per tutte le versioni di 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 - Da jQuery 1.9, $.browser.msienon è supportato. Fonte: http://api.jquery.com/jquery.browser/


14

Ci sono molti trucchi per gestire History e window.location.hash nei browser IE:

  • Come diceva la domanda originale, se passi dalla pagina a.html # b a a.html # c e quindi premi il pulsante Indietro, il browser non sa che la pagina è cambiata. Lasciatemi dire con un esempio: window.location.href sarà 'a.html # c', non importa se vi trovate in a.html # b o a.html # c.

  • In realtà, a.html # b e a.html # c sono memorizzati nella cronologia solo se gli elementi '<a name="#b">' e '<a name="#c">' esistono precedentemente nella pagina.

  • Tuttavia, se si inserisce un iframe all'interno di una pagina, passare da a.html # b a a.html # c in quell'iframe e quindi premere il pulsante Indietro, iframe.contentWindow.document.location.href cambia come previsto.

  • Se usi 'document.domain = qualcosa ' nel tuo codice, non puoi accedere a iframe.contentWindow.document.open () '(e molti History Manager lo fanno)

So che questa non è una vera risposta, ma forse le note di IE-History sono utili a qualcuno.




9

Potresti facilmente implementare un osservatore (il metodo "watch") sulla proprietà "hash" dell'oggetto "window.location".

Firefox ha una propria implementazione per guardare i cambiamenti di oggetto , ma se usi qualche altra implementazione (come Guarda le modifiche alle proprietà degli oggetti in JavaScript ) - per altri browser, questo funzionerà.

Il codice sarà simile al seguente:

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

Quindi puoi provarlo:

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

E ovviamente ciò attiverà la tua funzione di osservatore.


Migliore utilizzo: window.location.href invece di window.location.
Codebeat

3
Sta guardando window.location.hash, non window.location.
indefinito il

1
@BrianMortenson: secondo i documenti ( developer.mozilla.org/en-US/docs/JavaScript/Reference/… ) devi applicare watchall'oggetto che possiede la proprietà che sta cambiando e vuoi osservarla.
gion_13,

@ gion_13 Sì, è esattamente quello che stavo cercando di sottolineare. Per "Lui" intendevo te, ed era diretto al commento di Erwinus. Avrei dovuto essere più chiaro. Grazie per il tuo chiarimento.
indefinito,

7

Lo stavo usando in un'applicazione di reazione per fare in modo che l'URL mostrasse parametri diversi a seconda della vista su cui si trovava l'utente.

Ho visto il parametro hash usando

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

Poi

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

Ha funzionato a meraviglia, funziona con i pulsanti del browser avanti e indietro e anche nella cronologia del browser.


1
nella tua addEventListenerchiamata, dovresti rimuovere il ()dadoSomethingWithChangeFunction
Jason S

Potete fornire un motivo per rimuovere il ()? So che funzionerà con entrambi, e meno codice è per lo più l'opzione migliore, ma questo sembra esigente a meno che non ci sia una ragione sostanziale per eseguire il backup?
Sprose

6
? non dovrebbe funzionare con (). La addEventListenerfunzione richiede di passare una funzione. doSomethingWithChangeFunctionè una funzione. doSomethingWithChangeFunction()è il valore restituito di quella funzione, che in questo caso non è una funzione.
Jason S,

6

Un'implementazione decente è disponibile all'indirizzo http://code.google.com/p/reallysimplehistory/ . L'unico (ma anche) problema e bug che ha è: in Internet Explorer la modifica manuale dell'hash della posizione ripristinerà l'intero stack della cronologia (questo è un problema del browser e non può essere risolto).

Nota, Internet Explorer 8 ha il supporto per l'evento "hashchange" e, poiché sta diventando parte di HTML5, potresti aspettarti che altri browser raggiungano.


1

Un'altra grande implementazione è la cronologia di jQuery che utilizzerà l'evento onhashchange nativo se è supportato dal browser, in caso contrario utilizzerà un iframe o un intervallo appropriato per il browser per garantire che tutte le funzionalità previste siano emulate correttamente. Fornisce anche una bella interfaccia da associare a determinati stati.

Un altro progetto degno di nota è anche jQuery Ajaxy che è praticamente un'estensione per jQuery History per aggiungere ajax al mix. Come quando inizi a usare Ajax con gli hash diventa abbastanza complicato !


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);

Questo è tutto ... ora, ogni volta che premi i pulsanti indietro o avanti, la pagina verrà ricaricata secondo il nuovo valore di hash.


non usare le stringhe di
valutazione

1

Sto usando path.js per il mio routing lato client. L'ho trovato abbastanza succinto e leggero (è stato anche pubblicato su NPM) e fa uso della navigazione basata sull'hash.

path.js NPM

path.js GitHub


0

Ho usato un plugin jQuery, HUtil , e ho scritto una storia YUI come interfaccia su di esso.

Dai un'occhiata una volta. Se hai bisogno di aiuto, posso aiutarti.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.