On - window.location.hash - Changer?

558

J'utilise Ajax et le hachage pour la navigation.

Existe-t-il un moyen de vérifier si le window.location.hashchangement a été effectué comme ceci?

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

Cela fonctionne si je le vérifie lors du chargement du document.

Mais si j'ai une navigation basée sur #hash, cela ne fonctionne pas lorsque j'appuie sur le bouton de retour du navigateur (je passe donc de blah # 456 à blah # 123).

Il apparaît à l'intérieur de la zone d'adresse, mais je ne peux pas l'attraper avec JavaScript.

MilMike
la source
6
Découvrez
Xavi
9
History.js prend en charge la fonctionnalité de gestion d'état HTML5 (vous n'avez donc plus besoin d'utiliser des hachages!) Et la dégrade gracieusement vers les navigateurs HTML4 à l'aide de changements de hachage. Il prend en charge jQuery, MooTools et Prototype prêt à l'emploi.
balupton
@balupton, En fait, nous devons encore utiliser des hachages pour fournir à l'utilisateur une "nouvelle page" insérée dans son historique, sauf si vous utilisez le changement d'URL comme commentaire.
Pacerier
1
[Hasher] github.com/millermedeiros/hasher
Vishnoo Rath
hmm ... Je pense que vous avez besoin de moar jQuery
RaisingAgent

Réponses:

617

La seule façon de vraiment faire cela (et c'est ainsi que le fait `` l'histoire vraiment simple '') est de définir un intervalle qui continue de vérifier le hachage actuel et de le comparer à ce qu'il était auparavant, nous le faisons et laissons les abonnés s'abonner à un changement événement que nous déclenchons si le hachage change .. ce n'est pas parfait, mais les navigateurs ne prennent vraiment pas en charge cet événement nativement.


Mettez à jour pour garder cette réponse fraîche:

Si vous utilisez jQuery (qui aujourd'hui devrait être quelque peu fondamental pour la plupart), une bonne solution consiste à utiliser l'abstraction que jQuery vous donne en utilisant son système d'événements pour écouter les événements de hachage sur l'objet fenêtre.

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

La bonne chose ici est que vous pouvez écrire du code qui n'a même pas besoin de vous soucier de la prise en charge du changement de hachage, mais vous devez faire de la magie, sous la forme d'une fonctionnalité jQuery un peu moins connue des événements spéciaux jQuery .

Avec cette fonctionnalité, vous pouvez essentiellement exécuter du code d'installation pour n'importe quel événement, la première fois que quelqu'un tente d'utiliser l'événement de quelque manière que ce soit (comme la liaison à l'événement).

Dans ce code de configuration, vous pouvez vérifier la prise en charge du navigateur natif et si le navigateur ne l'implémente pas nativement, vous pouvez configurer une seule minuterie pour interroger les modifications et déclencher l'événement jQuery.

Cela libère complètement votre code de la nécessité de comprendre ce problème de support, la mise en œuvre d'un événement spécial de ce type est triviale (pour obtenir une version de travail simple à 98%), mais pourquoi le faire quand quelqu'un d'autre l'a déjà fait .

meandmycode
la source
7
IE8 le fait. Plus à venir
Sergey Ilinsky
28
La dernière version de Firefox (3.6 alpha) prend également en charge l'événement de changement de hachage natif: developer.mozilla.org/en/DOM/window.onhashchange Il vaut certainement la peine de vérifier cet événement, mais notez que IE8 vous le dira. existe quand il s'exécute en mode compatible IE7 .. malheureusement l'événement ne se déclenche pas .. vous devrez vérifier l'événement et que le navigateur ne semble pas être IE7 .. soupirer (ou tenter de déclencher l'événement avec la méthode fireEvent d'IE).
meandmycode
8
Au moment d'écrire ces lignes, WebKit déclenche également un hashchangeévénement, tandis que Safari (stable) ne le fait pas encore.
jholster
51
Juste pour ajouter une autre mise à jour, l' hashchangeévénement est désormais largement pris en charge: caniuse.com/#search=hash
Paystey
19
Suis-je le seul à penser que les réponses jQuery non sollicitées sont une douleur?
Luc
290

HTML5 spécifie un hashchangeévénement . Cet événement est désormais pris en charge par tous les navigateurs modernes . La prise en charge a été ajoutée dans les versions de navigateur suivantes:

  • Internet Explorer 8
  • Firefox 3.6
  • Chrome 5
  • Safari 5
  • Opera 10.6
Miles
la source
20
Mise à jour: FF 5, Safari 5 et Chrome 12 prennent en charge cet événement à partir de juin 2011.
james.garriss
2
Voici la page CanIUse pour le hachage . Voici le hachage sur quirksmode . Le support d'IE est bogué en ce qui concerne la sensibilité à la casse.
Tobu
3
@everybody, pas besoin de continuer à ajouter à la réponse dans la section des commentaires - c'est à cela que sert le bouton "Modifier". :)
Michael Martin-Smucker
15
utilisation:window.onhashchange = function() { doYourStuff(); }
Chris
4
Documentation MDN de l' événement hashchange .
Dabowheel
52

Notez que dans le cas d'Internet Explorer 7 et d'Internet Explorer 9, la ifdéclaration donnera true (pour "onhashchange" dans Windows), mais le window.onhashchangene se déclenchera jamais, il est donc préférable de stocker le hachage et de le vérifier toutes les 100 millisecondes s'il a changé ou non. pour toutes les versions d'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 - Depuis jQuery 1.9, $.browser.msien'est pas pris en charge. Source: http://api.jquery.com/jquery.browser/

Khan Salahuddin
la source
14

Il existe de nombreuses astuces pour gérer l'historique et window.location.hash dans les navigateurs IE:

  • Comme le disait la question d'origine, si vous passez de la page a.html # b à a.html # c, puis appuyez sur le bouton de retour, le navigateur ne sait pas que la page a changé. Permettez-moi de le dire avec un exemple: window.location.href sera 'a.html # c', peu importe si vous êtes dans a.html # b ou a.html # c.

  • En fait, a.html # b et a.html # c sont stockés dans l'historique uniquement si les éléments '<a name="#b">' et '<a name="#c">' existent déjà dans la page.

  • Cependant, si vous mettez un iframe à l'intérieur d'une page, naviguez d'un a.html # b vers un.html # c dans cet iframe, puis appuyez sur le bouton de retour, iframe.contentWindow.document.location.href change comme prévu.

  • Si vous utilisez «document.domain = quelque chose » dans votre code, vous ne pouvez pas accéder à iframe.contentWindow.document.open () »(et de nombreux gestionnaires d'historique le font)

Je sais que ce n'est pas une vraie réponse, mais peut-être que les notes de l'historique IE sont utiles à quelqu'un.

Sergio Cinos
la source
11

Ben Alman a un excellent plugin jQuery pour gérer cela: http://benalman.com/projects/jquery-hashchange-plugin/

Si vous n'utilisez pas jQuery, cela peut être une référence intéressante à disséquer.

CJ.
la source
Le plugin Ben Alman ne semble plus être maintenu. Il existe cependant un certain nombre de fourches.
Mnebuerquo
9

Vous pouvez facilement implémenter un observateur (la méthode "watch") sur la propriété "hash" de l'objet "window.location".

Firefox a sa propre implémentation pour regarder les changements d'objet , mais si vous utilisez une autre implémentation (telle que Watch for object properties changes in JavaScript ) - pour d'autres navigateurs, cela fera l'affaire.

Le code ressemblera à ceci:

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

Ensuite, vous pouvez le tester:

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

Et bien sûr, cela déclenchera votre fonction d'observateur.

gion_13
la source
Meilleure utilisation: window.location.href au lieu de window.location.
Codebeat
3
Il regarde window.location.hash, pas window.location.
indéfini le
1
@BrianMortenson: selon les documents ( developer.mozilla.org/en-US/docs/JavaScript/Reference/… ), vous devez appliquer watchà l'objet qui possède la propriété qui change et vous voulez l'observer.
gion_13
@ gion_13 Oui, c'est exactement ce que j'essayais de souligner. Par «Il», je voulais dire vous, et c'était dirigé vers le commentaire d'Erwinus. J'aurais dû être plus clair. Merci pour votre commentaire de clarification.
indéfini le
7

J'utilisais cela dans une application React pour que l'URL affiche différents paramètres en fonction de la vue de l'utilisateur.

J'ai regardé le paramètre de hachage en utilisant

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

alors

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

A travaillé un régal, fonctionne avec les boutons de navigation avant et arrière et également dans l'historique du navigateur.

Épinette
la source
1
dans votre addEventListenerappel, vous devez retirer le ()dedoSomethingWithChangeFunction
Jason S
Pouvez-vous fournir une raison pour supprimer le ()? Je sais que cela fonctionnera avec l'un ou l'autre, et moins de code est généralement la meilleure option, mais cela semble difficile à moins qu'il n'y ait une raison substantielle de le sauvegarder?
Sprose
6
? cela ne devrait pas fonctionner (). La addEventListenerfonction nécessite que vous passiez une fonction. doSomethingWithChangeFunctionest une fonction. doSomethingWithChangeFunction()est la valeur de retour de cette fonction, qui dans ce cas n'est pas une fonction.
Jason S
6

Une implémentation décente peut être trouvée sur http://code.google.com/p/reallysimplehistory/ . Le seul (mais aussi) problème et bogue qu'il présente est: dans Internet Explorer, la modification manuelle du hachage de l'emplacement réinitialisera toute la pile d'historique (il s'agit d'un problème de navigateur et il ne peut pas être résolu).

Remarque, Internet Explorer 8 prend en charge l'événement "hashchange", et comme il fait partie de HTML5, vous pouvez vous attendre à ce que d'autres navigateurs rattrapent leur retard.

Sergey Ilinsky
la source
1

Une autre excellente implémentation est l' historique jQuery qui utilisera l'événement onhashchange natif s'il est pris en charge par le navigateur, sinon il utilisera une iframe ou un intervalle approprié pour le navigateur pour garantir que toutes les fonctionnalités attendues sont émulées avec succès. Il fournit également une interface agréable pour se lier à certains états.

Un autre projet à noter également est jQuery Ajaxy qui est à peu près une extension pour jQuery History pour ajouter ajax au mix. Comme lorsque vous commencez à utiliser ajax avec des hachages, cela devient assez compliqué !

balupton
la source
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);

C'est tout ... maintenant, chaque fois que vous appuyez sur vos boutons Précédent ou Suivant, la page se rechargera selon la nouvelle valeur de hachage.

homme chauve-souris
la source
n'utilisez pas de chaînes eval
Vitim.us
1

J'ai utilisé path.js pour mon routage côté client. Je l'ai trouvé assez succinct et léger (il a également été publié sur NPM également) et utilise la navigation basée sur le hachage.

path.js NPM

path.js GitHub

À M
la source
0

J'ai utilisé un plugin jQuery, HUtil , et j'ai écrit une interface similaire à YUI History.

Vérifiez-le une fois. Si vous avez besoin d'aide, je peux vous aider.

moha297
la source