【发布时间】:2011-06-08 23:00:44
【问题描述】:
鉴于以下情况:
$(window).bind("popstate", function() {
alert('popstate');
});
第一次加载时,警报会在 FireFox 和 Chrome 中触发,但不是 Safari。这是为什么?其他人看到这个并且知道如何最好地解决这个问题?
【问题讨论】:
标签: javascript jquery html history
鉴于以下情况:
$(window).bind("popstate", function() {
alert('popstate');
});
第一次加载时,警报会在 FireFox 和 Chrome 中触发,但不是 Safari。这是为什么?其他人看到这个并且知道如何最好地解决这个问题?
【问题讨论】:
标签: javascript jquery html history
This answer to a similar question 建议在 popstate 事件处理程序中检查 event.state 的布尔值:
window.addEventListener('popstate', function(event) {
if (event.state) {
alert('!');
}
}, false);
您还可以将回调函数绑定到popstate 事件,如下所示:
window.onpopstate = callback();
查看 here 了解有关该解决方案的更多信息
【讨论】:
我将@Nobu & @Tamlyn 的答案转换成一个对象,我还添加了一点 通过添加“window.history.state !== null”来修复。在某些浏览器中 history.state 存在,但它为空,所以它不起作用。
/**
* 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;
...
});
感谢@Nobu! 谢谢@Tamlyn!
【讨论】:
现在情况发生了逆转。 Chrome 已修复该错误,现在在页面加载时触发 popstate,但 Firefox 4(自 RC 起)已偏离规范和now does not fire popstate!
更新:HTML5 规范于 2011 年更改为声明 popstate 不应在页面加载时触发。从 Firefox 4 和 Chrome 34 开始,Firefox 和 Chrome 现在都做了正确的事情。
【讨论】:
Webkit 中存在错误实现“popstate”事件的错误。看看这个解释问题的简单帖子(很酷的小秀和告诉):http://www.bcherry.net/playground/pushstate
我的建议是为 Safari 实现您自己的“popstate”事件跟踪器。像这样的:
$(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
});
您可以将该语句包装在浏览器测试中以检查 safari。更好地查看在 DOM 准备好时是否已触发“popstate”,然后应用内部函数来替换实现。您不希望发生的一件事是要触发两个 popstate 事件(复制您的事件处理程序逻辑,这是锁定 UI 的好方法)。
【讨论】:
在 webkit 中,popstate 事件在页面加载时触发。为避免这种情况,这个简单的解决方法对我有用:
每次我触发history.push(...) 时,我都会将class historypushed 添加到body-tag:
history.push(...);
$("body").addClass("historypushed");
当我触发 popstate 事件时,我会检查这个类:
$(window).bind('popstate', function(e) {
if($("body").hasClass("historypushed")) {
/* my code */
}
});
【讨论】:
避免此问题的一种简单方法是将 pushState 的第一个参数设置为 true,然后检查 onpopstate。类似于 pjax 示例,但更简单一些。下面的示例将为除第一个页面加载之外的每个 popstate 事件运行 doSomething()。
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();
}
});
}
}
【讨论】:
这是我的解决方法。
window.setTimeout(function() {
window.addEventListener('popstate', function() {
// ...
});
}, 1000);
【讨论】:
1 ms比较合适。
查看 pjax 中的代码。 pjax 是现在相当流行的开源库,所以下面的逻辑可能是最好的避免这个问题。
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
【讨论】: