如何让Firefox在从不同域名的页面返回时触发popstate事件?

7

我有一个简单的网页,它长这样:

<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事件,然后再次在我点击“返回”按钮时触发。Firefox仅会为更改哈希部分的链接触发事件(如果哈希链接相同,则仅在第一次执行此操作),如果我单击Yahoo链接然后单击“返回”按钮,则根本不会触发该事件。

因此,在Firefox中,是否有一种方法可以告诉我用户刚刚单击了“返回”按钮并从完全不同的站点和不同的域名着陆回我的页面?是否有另一种事件可用于此目的在Firefox中?(当我从yahoo.com返回时,加载事件也不会被触发。)

4个回答

12

如果想在使用后退(或前进)按钮返回最初加载的页面时触发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。我还没有考虑如何将它与我的方法结合起来。我只是通过添加一个页面unload处理程序来禁用它。

window.onunload = function(e) { }

这是一个很好的答案,可以解释如何使历史 API 在不同平台上工作相同,但它实际上没有回答 OP 的问题:如何确定用户是否实际上点击了“后退”按钮才回到该页面。使用您的示例,您可以告诉用户在 Chrome 和 Safari 上单击了后退按钮,因为在 onpopstate 处理程序中,mytag 将不为 null。但是在 Firefox 中,不会调用 onpopstate,因此似乎无法确定用户是返回到页面还是首次访问。那么,实际上有办法在 Firefox 中区分这一点吗? - Karmacon
1
@Karma:如果你禁用bfcache(请参见我的回答的最后一部分),那么Firefox应该表现得与Chrome类似。但是请阅读Boris Zbarsky的答案,以了解为什么你应该更喜欢Firefox的页面缓存而不是Chrome的行为方式。 - Sean Hogan
感谢@Sean Hogan。在重新阅读Firefox bfCaching后,我意识到它不适用于我们使用https的网站。Firefox总是刷新页面。 我想这方面我无能为力了。 - Karmacon
@Karma:我不知道https。谢谢你的提示。 - Sean Hogan

2

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

请注意,如果没有load事件,这意味着页面仍然具有与导航离开时完全相同的DOM和脚本执行环境。基本上就像用户暂时切换选项卡一样,而不是导航。

鉴于此,在这种情况下,您仍然想要获取事件吗?当用户切换回带有您的页面的选项卡时,是否会收到您要查找的事件?


0

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

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

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


0
我有同样的问题,并不得不深入规范中去找出为什么当使用返回按钮从不同域的页面返回时,popstate事件在任何浏览器中都不会触发。原来,在这种情况下,popstate不应该触发,因为文档的状态未改变,只有当状态改变时才应触发popstate。根据规范,要将状态更改设置为true,应执行以下操作:
“如果指定条目的文档具有最新条目,并且该条目不是指定条目,则将状态更改设置为true;否则将其设置为false。”
我的理解是,当我们从不同域的页面返回到我们的页面时,我们的页面没有最新条目,因为文档已更改,新文档尚无最新条目。再次引用规范:
“在浏览上下文中,每个文档也可以具有最新条目。这是用于最近遍历浏览上下文会话历史记录的该文档的条目。创建文档时,它最初没有最新条目。”
然而,仍然可以通过使用历史记录的pushState或replaceState方法在您的页面中的history.state中设置一个标志,并在页面加载时检查历史记录中是否存在此标志,以查看用户是否返回到您的页面。

如需了解更多关于popstate事件的内容,请参阅WHATWG的HTML规范,其中涉及历史遍历的部分: https://html.spec.whatwg.org/multipage/browsers.html#history-traversal


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接