【问题标题】:How can I ignore window.onpopstate on page load?如何在页面加载时忽略 window.onpopstate?
【发布时间】:2013-04-09 07:59:43
【问题描述】:

我在玩window.onpopstate,有件事让我有点恼火:

浏览器倾向于在页面加载时以不同方式处理 popstate 事件。 Chrome 和 Safari 总是在页面加载时发出 popstate 事件,但是 Firefox 没有。

source

我测试过,是的,在 Chrome 和 Safari 5.1+ 中,popstate 事件在页面加载时触发,但在 Firefox 或 IE10 中没有。

问题是,我只想收听popstate 用户单击后退前进按钮的事件(或通过javascript更改历史记录),但不想在页面加载上做任何事情。

换句话说,我想将popstate 事件与页面加载 与其他popstate 事件区分开来。

这是我迄今为止尝试过的(我正在使用 jQuery):

$(function() {
  console.log('document ready');

  setTimeout(function() {
    window.onpopstate = function(event) {
      // Do something here
    }, 10);
});

基本上我尝试将我的listener 函数绑定到popstate 足够晚,以便在页面加载时不绑定,只是稍后。

这似乎可行,但是,我不喜欢这种解决方案。我的意思是,我如何确定为 setTimeout 选择的 timeout 足够大,但又不会太大(因为我不希望它等待太多)。

希望有更聪明的解决方案!

【问题讨论】:

  • 这个错误似乎已经在 Chrome 上修复了。
  • 请更新您的问题,它只发生在今天的 safari 中。 Chrome 似乎已经解决了这个问题。
  • 这个错误的popstate 发生在onload 处理之后,这意味着1ms 总是足够推迟popstate 注册(因为JS 没有多线程和按注册顺序处理推迟的函数)。

标签: javascript jquery html


【解决方案1】:

popstate 事件处理程序中检查event.state 的布尔值:

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

为确保此操作有效,始终在调用 history.pushState()history.replaceState() 时指定非null 状态参数。此外,请考虑使用像 History.js 这样的包装库,它提供跨浏览器的一致行为。

【讨论】:

  • 是的,页面加载时 event.state 为空,但如果在没有定义状态的情况下调用 pushState,也可以为空,例如:history.pushState(null, null, url);
  • 所以总是定义一个状态或编写一个包装类(或使用existing one),这将使这些事情隐含。 HTML5 History API 的原生实现是不一致的,所以无论如何我们都不得不做出一些权衡。
  • 是的,我将使用包装类,并且在调用pushStatereplaceState 时从不使用null 作为状态。请用您最后的评论更新您的答案,以便我接受。感谢您的帮助。
  • 澄清一下:一定要调用history.pushState(state, null, url),不要在第一个参数上使用null。当 Safari 在页面加载时调用 popstate 时,event.state 将为 nil。这是区分初始页面加载与显式 pushState 调用的方法
  • 如果我在 page2 中执行 pushState,那么在触发 popstate 时,event.state 将是 null。如果我做pushState 2 次,我有一个有效的event.state 而卷土重来,但用户应该按返回按钮 3 次才能看到 page1
【解决方案2】:

我遇到了类似的问题,我必须验证以确保页面是否已完全加载。

我用过这样的东西:

var page_loaded = false;    
window.onpopstate = function(event){
    if(!page_loaded){
       page_loaded = true;
       return false;
     }
    //Continue With Your Code
}

【讨论】:

  • 我也在考虑这样的解决方案。问题是,窗口加载发生在第一个 onpopstate 之前,所以page_loaded 将始终为真。 (JSBin:jsbin.com/awidol/1/edit)
  • @TamasPap 解决方案可能会拒绝第一次执行代码,将 page_load 更改为 true,然后继续执行代码。
  • 是的,但是在 Fireworks 和 IE10 中第一个 onpopstate 不会发生。
  • @TamasPap 尝试检测浏览器并填充 if 条件以仅在执行此操作的浏览器上执行。
  • 我遇到了同样的问题,这就是我所做的,它不是一个明确的解决方案,但是它在 99% 的时间里都有效:var JUST_LOADED = true; setTimeout(function(){JUST_LOADED=false},399);
【解决方案3】:

要对popstate 事件做出反应,您需要将一些状态推送到会话历史记录中。

例如将这一行添加到文档准备部分:

history.pushState(null, null, window.location.pathname);

不理想,但它也适用于 Chrome、Firefox 和其他浏览器。

然后,当用户单击 BackForward 按钮时,以及手动调用 history.back()history.forward()history.go() 方法时,事件会正确触发。每次调用popstate 时,您都必须再次推送另一个状态以使其工作。

另见:

【讨论】:

    【解决方案4】:

    截至今天,似乎没有任何浏览器在页面加载时发出事件:

    浏览器过去在页面加载时处理 popstate 事件的方式不同,但现在它们的行为相同。 Firefox 从未在页面加载时发出 popstate 事件。 Chrome 一直到 34 版,而 Safari 一直到 10.0 版。

    来源:https://developer.mozilla.org/en-US/docs/Web/API/PopStateEvent

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-05-02
      • 1970-01-01
      • 2015-04-11
      • 2012-02-16
      • 1970-01-01
      • 1970-01-01
      • 2011-05-12
      • 1970-01-01
      相关资源
      最近更新 更多