90 votos

Popstate en la página ' s carga en cromo

Yo estoy usando el API de Historia para mi web app y tener un problema. Puedo hacer llamadas Ajax para actualizar algunos de los resultados en la página y la utilización de la historia.pushState() en el objeto de actualizar de la barra de ubicación del navegador sin necesidad de recargar la página. Entonces, claro, yo uso la ventana.popstate con el fin de restaurar el estado anterior cuando el botón es pulsado.

El problema es bien conocido - Chrome y Firefox tratar de que popstate evento de manera diferente. Mientras que Firefox no es el fuego en la primera carga, Chrome. Me gustaría tener Firefox-estilo y no se desencadena el evento de seguridad de la carga, ya que sólo las actualizaciones de los resultados con exactamente los mismos que en la carga. Hay una solución, excepto el uso de History.js? La razón por la que no se siente como que es de uso - necesita demasiadas librerías JS por sí mismo y, ya que la necesito para ser implementado en un CMS ya demasiado JS, me gustaría minimizar JS estoy poniendo en ella.

Así que, quisiera saber si hay una manera de hacer que Chrome no el fuego de 'popstate' en la carga o, tal vez, alguien trató de uso History.js como todas las bibliotecas puré juntos en un solo archivo.

46voto

Pavel Linkesch Puntos 1903

En Google Chrome en versión 19 la solución de @spliter dejó de funcionar. Como señala @johnnymire, history.state en Chrome 19 existe, pero es null.

Mi solución es añadir window.history.state! == null a comprobar si existe estado en window.history:

var popped = ('state' in window.history && window.history.state !== null), initialURL = location.href;

Lo he probado en todos los principales navegadores y en versiones cromo 19 y 18. Parece que funciona.

27voto

Sonny Piers Puntos 201

Utilizando setTimeout sólo no es una solución correcta, porque no tienes ni idea de cuánto tiempo tomará para que el contenido que se cargue por lo que es posible el evento popstate se emite después de que el tiempo de espera.

Aquí está mi solución: https://gist.github.com/3551566

 /*
* Necessary hack because WebKit fires a popstate event on document load
* https://code.google.com/p/chromium/issues/detail?id=63040
* https://bugs.webkit.org/process_bug.cgi
*/
window.addEventListener('load', function() {
  setTimeout(function() {
    window.addEventListener('popstate', function() {
      ...
    });
  }, 0);
});
 

25voto

Torben Puntos 1481

En caso de que usted no desea tomar medidas especiales para cada controlador de agregar a onpopstate, mi solución podría ser interesante para usted. Una gran ventaja de esta solución es también que onpopstate los eventos pueden ser tratados antes de que se carga la página se ha terminado.

Sólo este código se ejecuta una vez antes de agregar cualquier onpopstate controladores y todo debería funcionar como se esperaba (aka como en Mozilla ^^).

(function() {
    // There's nothing to do for older browsers ;)
    if (!window.addEventListener)
        return;
    var blockPopstateEvent = document.readyState!="complete";
    window.addEventListener("load", function() {
        // The timeout ensures that popstate-events will be unblocked right
        // after the load event occured, but not in the same event-loop cycle.
        setTimeout(function(){ blockPopstateEvent = false; }, 0);
    }, false);
    window.addEventListener("popstate", function(evt) {
        if (blockPopstateEvent && document.readyState=="complete") {
            evt.preventDefault();
            evt.stopImmediatePropagation();
        }
    }, false);
})();

Cómo funciona:

Chrome incendios de la onpopstate evento cuando el documento ha sido cargado. Esta no es la intención, así que bloquear popstate eventos hasta el primer bucle de eventos de ciclo después de que el documento ha sido cargado. Esto es hecho por el preventDefault y stopImmediatePropagation llamadas (a diferencia de stopPropagation stopImmediatePropagation detiene todos controlador de eventos llama al instante).

Sin embargo, desde que el documento de la readyState ya está en "completa" cuando Chrome incendios onpopstate erróneamente, que nos permiten opopstate eventos, los cuales han sido despedidos antes de la carga de documento se ha terminado para permitir onpopstate llamadas antes de que el documento ha sido cargado.

Actualización 2014-04-23: Corregido un error por el que popsate eventos han sido bloqueado si el script se ejecuta después de que la página se ha cargado.

24voto

spliter Puntos 3292

La solución se ha encontrado en jquery.pjax.js líneas 195-225:

 // Used to detect initial (useless) popstate.
// If history.state exists, assume browser isn't going to fire initial popstate.
var popped = ('state' in window.history), initialURL = location.href


// popstate handler takes care of the back and forward buttons
//
// You probably shouldn't use pjax on pages with other pushState
// stuff yet.
$(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

  var state = event.state

  if ( state && state.pjax ) {
    var container = state.pjax
    if ( $(container+'').length )
      $.pjax({
        url: state.url || location.href,
        fragment: state.fragment,
        container: container,
        push: false,
        timeout: state.timeout
      })
    else
      window.location = location.href
  }
})
 

14voto

Tom McKenzie Puntos 414

Una solución más directa que pjax reimplementar se establece una variable en pushState, y compruebe si la variable en popstate, por lo que el popstate inicial no se dispara de manera incompatible con carga (no una solución-jquery específico, simplemente usarlo para eventos):

 $(window).bind('popstate', function (ev){
  if (!window.history.ready && !ev.originalEvent.state)
    return; // workaround for popstate on load
}

// ... later ...

function doNavigation(nextPageId) {
  window.history.ready = true;

  history.pushState(state, null, 'content.php?id='+ nextPageId); 
  // ajax in content instead of loading server-side
}
 

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X