2011-01-14 13 views
28

Teniendo en cuenta lo siguiente:ventana se unen popstate

$(window).bind("popstate", function() { 
    alert('popstate'); 
}); 

Por primera carga, se dispare la alerta con Firefox y Chrome, pero no Safari. ¿Porqué es eso? ¿Alguien más ha visto esto y sabe cómo resolverlo mejor?

Gracias

Respuesta

15

La situación ahora está invertida. Chrome ha corregido el error y ahora dispara popstate en la carga de la página, pero Firefox 4 (desde RC) se ha apartado de la especificación y now does not fire popstate.

ACTUALIZACIÓN: La especificación de HTML5 se cambió en 2011 para indicar que el estado emergente no debería activarse en la carga de la página. Tanto Firefox como Chrome ahora hacen lo correcto a partir de Firefox 4 y Chrome 34.

+2

La especificación de HTML5 se cambió en 2011 para indicar que el estado emergente no debería activarse en la carga de la página. La votación ascendente https://code.google.com/p/chromium/issues/detail?id=63040 es la mejor manera de que Chrome vuelva a cumplir con el estándar. Google sabe desde hace dos años que el comportamiento de Chrome no es correcto. – Dave

2

había un fallo en Webkit que implementó incorrectamente el evento "popstate". Echa un vistazo a esta simple publicación que explica el problema (pequeño espectáculo y contar): http://www.bcherry.net/playground/pushstate

Mi sugerencia sería implementar tu propio rastreador de eventos "popstate" para Safari. Algo como esto:

$(window).load(function(){ 
    function fire_popstate(){ 
    $(this).trigger("popstate"); // fire it when the page first loads 
    } 
    var lasthash = window.location.hash; 
    setInterval(function(){ 
    var currenthash = window.location.hash; 
    if(lasthash != currenthash){ 
     fire_popstate(); 
    } 
    }, 500);//check every half second if the url has changed 
}); 

Puede envolver esa declaración en una prueba del navegador para comprobar si hay safari. Mejor aún, vea si se ha disparado "estado emergente" cuando el DOM está listo y luego aplique la función interna para reemplazar la implementación. Lo único que no quiere que suceda es tener dos eventos de estado emergente para ser activados (duplicar la lógica de su controlador de eventos, una gran manera de bloquear la interfaz de usuario).

45

Vea el código de pjax. pjax es una biblioteca de código abierto bastante popular ahora, por lo que la siguiente lógica podría ser la mejor para evitar este problema.

var popped = ('state' in window.history), initialURL = location.href 
$(window).bind('popstate', function(event) { 
    // Ignore inital popstate that some browsers fire on page load 
    var initialPop = !popped && location.href == initialURL 
    popped = true 
    if (initialPop) return 
    ... 

https://github.com/defunkt/jquery-pjax/blob/master/jquery.pjax.js

0

Esta es mi solución.

window.setTimeout(function() { 
    window.addEventListener('popstate', function() { 
    // ... 
    }); 
}, 1000); 
+3

¿Qué hace esto? Tal vez en lugar de publicarlo [en todas partes] (http://stackoverflow.com/a/8378425/74865) debería explicarlo por una vez. – drozzy

+2

@drozzy ¡Claro! Este fragmento de código agrega un nuevo detector de eventos al evento popstate (después de 1 segundo). Con este enfoque, el evento popstate no se dispara en la carga de la página. – Baggz

+2

@Baggz, de acuerdo con [una demostración de Inmersión en html5] (http://diveintohtml5.info/examples/history/casey.html), '1 ms' es más apropiado. –

17

En webkit, el evento popstate se activa en la carga de la página. Para evitar esto, este trabajo fácil de evitar que funciona para mí:

Cada vez que enciendo history.push(...) añado el classhistorypushed a la body -tag:

history.push(...); 
$("body").addClass("historypushed"); 

Cuando activar el evento popstate, puedo comprobar para esta clase:

$(window).bind('popstate', function(e) { 
if($("body").hasClass("historypushed")) { 
    /* my code */ 
} 
}); 
+0

¡Inteligente! Gracias por eso. – griffla

+0

Funciona muy bien, gracias! – tlaverdure

+0

buena solución :-) – milushov

3

Una manera fácil de evitar este problema es establecer el primer argumento en pushState a continuación, comprobar la verdadera contra onpopstate. Similar al ejemplo de pjax pero un poco más directo. El siguiente ejemplo ejecutará doSomething() para cada evento de estado emergente excepto para la carga de la primera página.

function setupPopState() { 
    if (history.popState) { 
    # immediately replace state to ensure popstate works for inital page 
    history.replaceState(true, null, window.location.pathname); 

    $(window).bind('popstate', function(event) { 
     if (event.originalEvent.state) { 
     doSomething(); 
     } 
    }); 
    } 
} 
0

convierto @Nobu & @Tamlyn respuestas en un objeto, también añadir un poco de solución mediante la adición de "window.history.state! == null". En algunos navegadores, existe history.state, pero es nulo, por lo que no funcionaba.

/** 
 
* The HTML5 spec was changed in 2011 to state popstate should not 
 
* fired on page load. Chrome(34) & Firefox(4) has fixed the bug but 
 
* some browsers (e.g. Safari 5.1.7) are still fire the popstate on 
 
* the page load. This object created from the Pjax Library to handle 
 
* this issue. 
 
*/ 
 
var popstatePageloadFix = { 
 
\t popped : ('state' in window.history && window.history.state !== null), 
 
\t initialUrl : location.href, 
 
\t initialPop : false, 
 
\t init : function() { 
 
\t \t this.initialPop = !this.popped && location.href == this.initialUrl; 
 
\t \t this.popped = true; 
 
\t \t return this.initialPop; 
 
\t } 
 
}; 
 

 
$(window).on("popstate", function (event) { 
 
\t 
 
\t // Ignore initial popstate that some browsers fire on page load 
 
\t if (popstatePageloadFix.init()) return; 
 
\t 
 
\t ... 
 

 
});

Gracias @Nobu! Gracias @Tamlyn!

0

This answer to a similar question sugiere para comprobar la verdad booleano de event.state en el controlador popstate evento:

window.addEventListener('popstate', function(event) { 
    if (event.state) { 
     alert('!'); 
    } 
}, false); 

También puede atar su función de devolución de llamada para popstate evento como este:

window.onpopstate = callback(); 

Verificar here para obtener más información sobre esa solución