On - window.location.hash - ¿Cambiar?


558

Estoy usando Ajax y hash para la navegación.

¿Hay alguna manera de verificar si ha window.location.hashcambiado así?

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

Funciona si lo reviso cuando se carga el documento.

Pero si tengo una navegación basada en #hash no funciona cuando presiono el botón Atrás en el navegador (así que salto de blah # 456 a blah # 123).

Se muestra dentro del cuadro de dirección, pero no puedo detectarlo con JavaScript.



99
History.js es compatible con la funcionalidad de administración de estado HTML5 (por lo que ya no necesita usar hashes) y lo degrada con gracia a los navegadores HTML4 utilizando hashchanges. Es compatible con jQuery, MooTools y Prototype de fábrica.
Balupton

@balupton, En realidad, todavía necesitamos usar hashes para proporcionar comentarios al usuario de que se ha insertado una "nueva página" en su historial, a menos que use el cambio de URL como comentario.
Pacerier


hmm ... creo que necesitas moar jQuery
RaisingAgent

Respuestas:


617

La única forma de hacer esto realmente (y es cómo la 'historia realmente simple' hace esto), es estableciendo un intervalo que siga verificando el hash actual y comparándolo con lo que era antes, hacemos esto y permitimos que los suscriptores se suscriban a un cambio evento que activamos si el hash cambia ... no es perfecto, pero los navegadores realmente no admiten este evento de forma nativa.


Actualice para mantener esta respuesta fresca:

Si está utilizando jQuery (que hoy debería ser algo fundamental para la mayoría), entonces una buena solución es utilizar la abstracción que le proporciona jQuery utilizando su sistema de eventos para escuchar eventos de cambio de hash en el objeto de la ventana.

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

Lo bueno aquí es que puede escribir código que ni siquiera tiene que preocuparse por el soporte de hashchange, sin embargo, necesita hacer algo de magia, en forma de una característica jQuery algo menos conocida de eventos especiales jQuery .

Con esta característica, esencialmente puede ejecutar algún código de configuración para cualquier evento, la primera vez que alguien intenta usar el evento de alguna manera (como el enlace al evento).

En este código de configuración, puede verificar la compatibilidad con el navegador nativo y, si el navegador no lo implementa de forma nativa, puede configurar un solo temporizador para sondear los cambios y activar el evento jQuery.

Esto libera por completo su código de la necesidad de comprender este problema de soporte, la implementación de un evento especial de este tipo es trivial (para obtener una versión de trabajo simple del 98%), pero ¿por qué hacerlo cuando alguien más ya lo ha hecho ?


77
IE8 lo hace. Más por venir
Sergey Ilinsky

28
La última versión de Firefox (3.6 alpha) ahora también admite el evento de cambio hash nativo: developer.mozilla.org/en/DOM/window.onhashchange Sin duda vale la pena hacer una comprobación para este evento, pero tenga en cuenta que IE8 le informará el evento existe cuando se ejecuta en modo de compatibilidad con IE7 ... lamentablemente, el evento no se dispara ... deberá verificar el evento y que el navegador no parece ser IE7 ... suspiro (o intentar activar el evento) con el método fireEvent de IE).
meandmycode

8
Al momento de escribir, WebKit también dispara hashchangeeventos, mientras que Safari (estable) aún no.
jholster

51
Solo para agregar otra actualización, el hashchangeevento ahora es ampliamente compatible: caniuse.com/#search=hash
Paystey

19
¿Soy el único que piensa que las respuestas no solicitadas de jQuery son un dolor?
Luc

290

HTML5 especifica un hashchangeevento . Este evento ahora es compatible con todos los navegadores modernos . Se agregó soporte en las siguientes versiones del navegador:

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

20
Actualización: FF 5, Safari 5 y Chrome 12 admiten este evento a partir de junio de 2011.
james.garriss

2
Aquí está la página CanIUse para hashchange . Aquí hay cambio de hash en quirksmode . El soporte de IE es defectuoso con respecto a mayúsculas y minúsculas.
Tobu

3
@todos los demás, no es necesario que sigas agregando la respuesta en la sección de comentarios, para eso está el botón "Editar". :)
Michael Martin-Smucker

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

44
Documentación MDN del evento hashchange .
Dabowheel

52

Tenga en cuenta que en el caso de Internet Explorer 7 e Internet Explorer 9, la ifdeclaración dará verdadero (para "onhashchange" en Windows), pero window.onhashchangenunca se disparará, por lo que es mejor almacenar hash y verificarlo después de cada 100 milisegundos, ya sea que haya cambiado o no. para todas las versiones de 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);
    }

EDITAR: desde jQuery 1.9, $.browser.msieno es compatible. Fuente: http://api.jquery.com/jquery.browser/


14

Hay muchos trucos para tratar con History y window.location.hash en los navegadores IE:

  • Como decía la pregunta original, si va de la página a.html # b a a.html # c, y luego presiona el botón Atrás, el navegador no sabe que la página ha cambiado. Permítanme decirlo con un ejemplo: window.location.href será 'a.html # c', sin importar si está en a.html # b o a.html # c.

  • En realidad, a.html # by a.html # c se almacenan en el historial solo si los elementos '<a name="#b">' y '<a name="#c">' existen previamente en la página.

  • Sin embargo, si coloca un iframe dentro de una página, navegue de a.html # b a a.html # c en ese iframe y luego presione el botón Atrás, iframe.contentWindow.document.location.href cambia como se esperaba.

  • Si usa 'document.domain = something ' en su código, entonces no puede acceder a iframe.contentWindow.document.open () '(y muchos administradores de historia lo hacen)

Sé que esta no es una respuesta real, pero quizás las notas de IE-History sean útiles para alguien.




9

Puede implementar fácilmente un observador (el método "watch") en la propiedad "hash" del objeto "window.location".

Firefox tiene su propia implementación para observar los cambios de objeto , pero si usa alguna otra implementación (como Observar cambios de propiedades de objetos en JavaScript ), para otros navegadores, eso será el truco.

El código se verá así:

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

Entonces puedes probarlo:

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

Y, por supuesto, eso activará su función de observador.


Mejor uso: window.location.href en lugar de window.location.
Codebeat

3
Él está mirando window.location.hash, no window.location.
indefinido el

1
@BrianMortenson: de acuerdo con los documentos ( developer.mozilla.org/en-US/docs/JavaScript/Reference/… ) debe aplicar watchal objeto que posee la propiedad que está cambiando y desea observarlo.
gion_13

@ gion_13 Sí, eso es exactamente lo que estaba tratando de señalar. Por "Él" me refería a ti, y estaba dirigido al comentario de Erwinus. Debería haber sido más claro. Gracias por tu comentario aclaratorio.
indefinido el

7

Estaba usando esto en una aplicación de reacción para hacer que la URL muestre diferentes parámetros dependiendo de la vista en la que se encontraba el usuario.

Vi el parámetro hash usando

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

Entonces

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

Trabajó de maravilla, funciona con los botones del navegador hacia adelante y hacia atrás y también en el historial del navegador.


1
en su addEventListenerllamada, se debe quitar la ()dedoSomethingWithChangeFunction
Jason S

¿Puede proporcionar una razón para eliminar el ()? Sé que funcionará con cualquiera de los dos, y menos código es en su mayoría la mejor opción, pero esto parece exigente a menos que haya una razón sustancial para respaldar esto.
Sprose

66
? no se debe trabajar con (). La addEventListenerfunción requiere que pases una función. doSomethingWithChangeFunctionEs una función. doSomethingWithChangeFunction()es el valor de retorno de esa función, que en este caso no es una función.
Jason S

6

Se puede encontrar una implementación decente en http://code.google.com/p/reallysimplehistory/ . El único (pero también) problema y error que tiene es: en Internet Explorer, la modificación manual del hash de ubicación restablecerá toda la pila del historial (este es un problema del navegador y no se puede resolver).

Tenga en cuenta que Internet Explorer 8 tiene soporte para el evento "hashchange", y dado que se está convirtiendo en parte de HTML5, puede esperar que otros navegadores se pongan al día.


1

Otra gran implementación es jQuery History, que utilizará el evento onhashchange nativo si es compatible con el navegador; de lo contrario, utilizará un iframe o intervalo apropiado para que el navegador garantice que toda la funcionalidad esperada se emule con éxito. También proporciona una buena interfaz para vincularse a ciertos estados.

Otro proyecto que vale la pena destacar también es jQuery Ajaxy, que es más o menos una extensión para jQuery History para agregar ajax a la mezcla. Como cuando comienzas a usar ajax con hashes, ¡es bastante 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);

Eso es todo ... ahora, cada vez que presionas los botones hacia atrás o hacia adelante, la página se volverá a cargar según el nuevo valor hash.


no use cadenas eval
Vitim.us

1

He estado usando path.js para mi enrutamiento del lado del cliente. He descubierto que es bastante sucinto y ligero (también se ha publicado en NPM), y hace uso de la navegación basada en hash.

path.js NPM

path.js GitHub


0

Usé un complemento jQuery, HUtil , y escribí un YUI interfaz similar a la de History.

Compruébalo una vez. Si necesitas ayuda, puedo ayudarte.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.