窗口绑定POPSTATE

时间:2011-01-14 05:10:28

标签: javascript jquery html5 history

鉴于以下内容:

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

首次加载时,警报会触发FireFox和Chrome,但不会触发Safari。这是为什么?其他人看过这个,知道如何最好地解决这个问题吗?

8 个答案:

答案 0 :(得分:45)

请参阅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

答案 1 :(得分:17)

在webkit中,popstate事件在页面加载时触发。为了避免这种情况,这个简单的工作对我有用:

每当我点火history.push(...)时,我都会将class historypushed 添加到body - 标记中:

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

当我触发popstate事件时,我会检查这个类:

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

答案 2 :(得分:15)

现在情况正好相反。 Chrome修复了该错误,现在在页面加载时触发popstate,但Firefox 4(自RC以来)已脱离规范和now does not fire popstate

更新:HTML5规范在2011年更改为状态popstate不应在页面加载时触发。从Firefox 4和Chrome 34开始,Firefox和Chrome现在都做对了。

答案 3 :(得分:3)

避免此问题的一种简单方法是将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();
      }
    });
  }
}

答案 4 :(得分:2)

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的好方法)。

答案 5 :(得分:0)

这是我的解决方法。

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

答案 6 :(得分:0)

我转换@Nobu& @Tamlyn回答了一个对象,我也加了一点 通过添加" window.history.state!== null"来修复。在某些浏览器中 history.state存在,但它为null,因此它无效。



/**
 * 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!

答案 7 :(得分:0)

This answer to a similar question 建议检查event.state事件处理程序中popstate的布尔真值:

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

您还可以将回调函数绑定到popstate事件,如下所示:

window.onpopstate = callback();

检查 here ,了解有关该解决方案的更多信息