【问题标题】:How to get Firefox to fire the popstate event when going back from a page on a different domain?从不同域的页面返回时,如何让 Firefox 触发 popstate 事件?
【发布时间】:2012-10-11 13:18:55
【问题描述】:

我有一个简单的网页,即:

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>History hacks</title>
<script>
window.onpopstate = function (e) {
    alert("location: " + document.location + ", state: " + JSON.stringify(e.state));
}
window.onload = function (e) {
    alert('page loaded');
}
</script>
</head>
<body>
<p> <a href="http://www.yahoo.com">Yahoo</a> <a href="#part1">Part 1</a></p>
</body>
</html>

现在,关于 Chrome 和 Firefox 如何触发 popstate 事件存在许多差异(当我开始测试 IE 时,我不禁想到我所面临的问题),但这里给我带来的问题是每当我点击这两个链接中的任何一个时,Chrome 都会触发popstate event,然后当我点击返回按钮时再次触发。 Firefox 将触发更改哈希部分的链接的事件(如果哈希链接相同,则仅是第一次),如果我单击 Yahoo 链接然后单击后退按钮,则根本不会触发它。

那么有没有一种方法可以让我在 Firefox 中判断用户刚刚从不同域上的完全不同站点返回并返回我的页面?在 Firefox 中是否有其他事件可以用于此目的? (当我从 yahoo.com 返回时,加载事件也不会被触发。)

【问题讨论】:

    标签: javascript firefox dom-events popstate


    【解决方案1】:

    要在使用后退(或前进)按钮转到初始页面加载时获得popstate 事件,请使用replaceState()

    window.onload = function(e) {
      history.replaceState(null, null, document.URL);
    }
    

    要忽略 Chrome 在页面加载时生成的初始 popstate,您可以在调用 pushState / replaceState 时标记状态,例如

    history.pushState({myTag: true}, null, url);
    

    然后您的 popstate 处理程序只过滤 myTag

    window.onpopstate = function(e) { 
      if (!e.state.myTag) return; // none of my business
      // code to handle popstate 
    }
    

    您可以将这两者结合起来以获得简单的跨浏览器解决方案:

    window.onpopstate = function(e) { 
      if (!e.state.myTag) return; // none of my business
      // code to handle popstate 
    }
    
    window.onload = function(e) {
      history.replaceState({myTag: true}, null, document.URL);
    }
    

    @Boris Zbarsky 详细介绍了 bfcache。我还没有想过如何将它与我的方法结合起来。我只是通过adding a page unload handler禁用它

    window.onunload = function(e) { }
    

    【讨论】:

    • 这是解释如何使历史 API 在相同的跨平台上工作的一个很好的答案,但它实际上并没有回答 OP 的问题:如何判断用户是否真的点击了“返回” " 最终出现在页面上。 使用您的示例,您可以判断用户在 Chrome 和 Safari 中单击了返回,因为 mytag 在 onpopstate 处理程序中不会为空。但是在 Firefox 中,不会调用 onpopstate,因此似乎无法确定用户是返回页面还是第一次访问。那么实际上有什么方法可以在 Firefox 中区分这一点吗?
    • @Karma:如果您禁用 bfcache(请参阅我回答的最后一部分),那么 Firefox 的行为应该与 Chrome 类似。但是请阅读 Boris Zbarsky 的回答,以很好地说明为什么您应该更喜欢 Firefox 的页面缓存而不是 Chrome 的行为。
    • 感谢@Sean Hogan。在重新阅读 Firefox bfCaching 后,我意识到它在我的网站上不起作用,因为我们使用 https。 Firefox 总是刷新页面。我想我对此无能为力。
    • @Karma:我不知道 https。感谢您的提示。
    【解决方案2】:

    如果您想在返回页面时收到通知,即使页面缓存在页面缓存中,您可能正在寻找 pageshow 事件。

    请注意,如果没有加载事件,这也意味着页面仍然具有与导航离开时完全相同的 DOM 和脚本执行环境。基本上就像用户切换了一段时间的标签,而不是导航。

    因此,在这种情况下,您还想参加活动吗?当用户切换回包含您的页面的选项卡时,您是否收到了您要查找的事件?

    【讨论】:

      【解决方案3】:

      在卸载之前我重新加载我的页面(以获取初始状态)然后设置新的 href

      window.onunload = function(e) {
        location.reload();
        location.href = **new_url** ;
      }

      我必须这样做,因为 Firefox 会保存我页面的最后状态并恢复它而不是重新创建它。

      【讨论】:

        【解决方案4】:

        我有同样的问题,不得不深入研究规范,以找出当使用后退按钮从不同域的页面返回时,为什么 popstate 事件不会在任何浏览器中触发。事实证明,在这种情况下 popstate 不应该触发,因为文档的 state changed 不是 true,并且 popstate 应该仅在 state changed 为 true 时触发。对于将状态更改为 true 的规范说:

        如果指定条目的 Document 有最新条目,并且该条目不是指定条目,则令 state changed 为 true;否则为假。

        我的理解是,当我们从不同域的页面返回到我们的页面时,我们的页面没有最新的条目,因为文档已经更改并且新文档还没有最新的条目。再次来自规范:

        浏览上下文中的每个文档也可以有一个最新条目。这是浏览上下文的会话历史最近被遍历到的那个 Document 的条目。创建文档时,它最初没有最新条目。

        但是,仍然有一种方法可以查看用户是否返回到您的页面,方法是使用 history 的 pushState 或 replaceState 方法在页面的 history.state 中设置一个标志,并在页面加载时检查 history.state 中是否存在此标志.

        更多阅读 WHATWG 的 HTML 规范中处理 popstate 事件的部分: https://html.spec.whatwg.org/multipage/browsers.html#history-traversal

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-04-20
          • 2012-06-12
          • 1970-01-01
          • 2021-07-16
          • 1970-01-01
          • 1970-01-01
          • 2020-07-05
          • 1970-01-01
          相关资源
          最近更新 更多