Compte tenu des éléments suivants:
$(window).bind("popstate", function() {
alert('popstate');
});
Au premier chargement, l'alerte se déclenche avec FireFox et Chrome mais pas Safari. Pourquoi cela? Quelqu'un d'autre a vu cela et sait comment le résoudre au mieux?
La situation est désormais inversée. Chrome a corrigé le bogue et déclenche maintenant le popstate au chargement de la page mais Firefox 4 (depuis RC) s'est écarté de la spécification et ne déclenche plus le popstate !
[~ # ~] mise à jour [~ # ~] : la spécification HTML5 a été modifiée en 2011 pour indiquer que le popstate ne doit pas être déclenché au chargement de la page. Firefox et Chrome font maintenant la bonne chose à partir de Firefox 4 et Chrome 34 .
Voir le code de pjax. pjax est une bibliothèque open source assez populaire maintenant, donc la logique ci-dessous pourrait être la meilleure pour éviter ce problème.
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
Dans webkit, l'événement popstate est déclenché au chargement de la page. Pour éviter cela, cette solution simple fonctionne pour moi:
Chaque fois que je déclenche history.Push(...)
j'ajoute le class
historypushed à la balise body
-:
history.Push(...);
$("body").addClass("historypushed");
Lorsque je déclenche l'événement popstate, je vérifie cette classe:
$(window).bind('popstate', function(e) {
if($("body").hasClass("historypushed")) {
/* my code */
}
});
Un moyen simple d'éviter ce problème consiste à définir le premier argument de pushState sur true, puis à vérifier par rapport à onpopstate. Similaire à l'exemple pjax mais un peu plus simple. L'exemple ci-dessous exécutera doSomething () pour chaque événement popstate à l'exception du premier chargement de page.
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();
}
});
}
}
Il y avait un bogue dans Webkit qui implémentait incorrectement l'événement "popstate". Consultez ce post simple expliquant le problème (petit show et tell cool): http://www.bcherry.net/playground/pushstate
Ma suggestion serait d'implémenter votre propre tracker d'événement "popstate" pour Safari. Quelque chose comme ça:
$(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
});
Vous pouvez envelopper cette déclaration dans un test de navigateur pour vérifier le safari. Mieux encore, voyez si "popstate" a été déclenché au moment où le DOM est prêt, puis appliquez la fonction interne pour remplacer l'implémentation. La seule chose que vous ne voulez pas, c'est d'avoir deux événements popstate à déclencher (duplication de la logique de votre gestionnaire d'événements, excellent moyen de verrouiller l'interface utilisateur).
Ceci est ma solution de contournement.
window.setTimeout(function() {
window.addEventListener('popstate', function() {
// ...
});
}, 1000);
Cette réponse à une question similaire suggère de vérifier la vérité booléenne de event.state
dans le gestionnaire d'événements popstate
:
window.addEventListener('popstate', function(event) {
if (event.state) {
alert('!');
}
}, false);
Vous pouvez également lier votre fonction de rappel à un événement popstate
comme ceci:
window.onpopstate = callback();
Consultez ici pour plus d'informations sur cette solution
Je convertis les réponses @Nobu & @Tamlyn en un objet, j'ajoute également un petit correctif en ajoutant "window.history.state! == null". Dans certains navigateurs, history.state existe, mais il est nul, donc cela ne fonctionnait pas.
/**
* 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 = {
popped : ('state' in window.history && window.history.state !== null),
initialUrl : location.href,
initialPop : false,
init : function() {
this.initialPop = !this.popped && location.href == this.initialUrl;
this.popped = true;
return this.initialPop;
}
};
$(window).on("popstate", function (event) {
// Ignore initial popstate that some browsers fire on page load
if ( popstatePageloadFix.init() ) return;
...
});
Merci @Nobu! Merci @Tamlyn!