回到 Firefox 历史后,JavaScript 将无法运行
Posted
技术标签:
【中文标题】回到 Firefox 历史后,JavaScript 将无法运行【英文标题】:After travelling back in Firefox history, JavaScript won't run 【发布时间】:2011-02-07 23:01:37 【问题描述】:当我使用 Firefox 上的后退按钮访问之前访问过的页面时,该页面上的脚本不会再次运行。
是否有任何修复/解决方法让脚本在第二次查看页面时再次执行?
请注意,我已经在 Google Chrome 和 Internet Explorer 上测试了相同的页面,它们可以正常工作。
这是我用来测试问题的文件和步骤:
(导航到 0.html,点击进入 1.html,返回按钮)
0.html
<html><body>
<script>
window.onload = function() alert('window.onload alert'); ;
alert('inline alert');
</script>
<a href="1.html">Click Me!</a>
</body></html>
1.html
<html><body>
<p>Go BACK!</p>
</body></html>
【问题讨论】:
【参考方案1】:设置一个空函数在 window.onunload 上调用:
window.onunload = function();
例如
<html><body>
<script type="text/javascript">
window.onload = function() alert('window.onload alert'); ;
window.onunload = function();
alert('inline alert');
</script>
<a href="1.html">Click Me!</a>
</body></html>
来源: http://www.firefoxanswer.com/firefox/672-firefoxanswer.html(Archived Version)
【讨论】:
谢谢,它有效。关于默认 onunload 处理程序做什么的任何提示? (例如,我是否在这里覆盖了某种默认行为?) 好的,谢谢,我会调查的。再次感谢,这个问题困扰了我一段时间:) 有人知道为什么 FireFox 需要这个而其他浏览器不需要吗? 你并没有覆盖任何东西,这只是防止 Firefox 将页面缓存在 Back-Forward Cache (bfcache) 中。 developer.mozilla.org/en/DOM/window.onunloaddeveloper.mozilla.org/En/Using_Firefox_1.5_caching 虽然它应该破坏 bfcache 不幸的是它似乎仍然记得上一页 - 具体来说,当您返回时,加载的 iframe url 会再次加载,如果需要生成的内容要放置在框架中,似乎没有跨浏览器的方式来重新刷新。【参考方案2】:当我使用 Firefox 上的后退按钮访问之前访问过的页面时,该页面上的脚本将不会再次运行。
这是正确的,这是一件好事。
当您在 Firefox(以及 Safari 和 Opera)中点击链接时,它不会立即破坏您的页面以进入下一个页面。它使页面保持完整,只是将其隐藏起来。如果您点击后退按钮,它将重新显示旧页面,而无需再次加载文档;这要快得多,从而为用户带来更流畅的后退/前进页面转换。
此功能称为bfcache。
您在用户之前加载和使用页面期间添加到页面的任何内容仍然存在。您附加到页面元素的任何事件处理程序仍将附加。您设置的任何超时/间隔仍然有效。因此,您几乎没有任何理由需要知道您已被隐藏并重新显示。再次调用onload
或内联脚本代码是错误的,因为您在该函数中执行的任何绑定和内容生成都将在相同内容上第二次执行,这可能会导致灾难性的后果。 (例如,内联脚本中的document.write
会完全破坏页面。)
写信给window.onunload
的原因是实现 bfcache 的浏览器已经决定 — 为了与确实需要知道何时被丢弃的页面兼容 — 任何声明有兴趣知道何时被丢弃的页面onunload
发生将导致 bfcache 被禁用。当您返回该页面时,该页面将重新加载,而不是从 bfcache 中获取。
所以如果你设置window.onunload= function() ;
,你实际上是在故意破坏bfcache。这将导致您的网页浏览缓慢,除非万不得已,否则不应使用。
如果您确实需要知道用户何时离开或返回您的页面,而不会弄乱 bfcache,则可以改为捕获 onpageshow
和 onpagehide
事件:
window.onload=window.onpageshow= function()
alert('Hello!');
;
【讨论】:
我的问题是 bfcache 不会缓存所有页面,所以我必须重新运行 js 来重建丢失的内容。所以翻动整个页面可能没问题。无论如何,我没有使用 window.onload 事件,我使用的是 jQuery document.ready 事件。您知道一种仍然可以使用 document.ready 并避免此问题的方法吗? bfcache 通常应该返回整个页面,就像它离开时一样。从上一页返回后缺少什么内容? (测试用例?)document.ready
的工作方式与window.onload
基本相同(对于某些浏览器,它们是相同的事件)。
这不是一件好事,因为它不会再次运行 javascript,考虑到它已缓存......但实际上并没有缓存 javascript 之前所做的更改。如果 javascript 在页面加载时淡入某个元素,则在历史中访问时它不会再次淡入淡出它......但是会再次以 0 不透明度启动它,撤消 javascript 所做的事情!它必须是全部或全部。如果您想在不再次运行 javascript 的情况下缓存页面,则必须在 javascript 运行后缓存页面的完整状态!
@Jimbo:请测试用例。 bfcache 旨在(并且在我所见过的每种情况下,确实如此)通过隐藏/显示保留 DOM 的确切状态。当页面返回时,已淡入的元素将保持不透明,除非运行其他脚本再次隐藏它。
@bobince - 使用 CSS 文件创建一个元素,将不透明度设置为零,然后使用一些 jQuery 使其淡入准备好的文档。回到历史时,它将重新应用样式表 CSS(零),而不保留 JS 在淡入时添加到样式属性的 opacity:1。第一次访问页面时,元素将从零淡入到 1。转到另一个页面并回击,它就会完全透明地坐在那里。【参考方案3】:
您可以检查pageshow
事件的persisted
属性。它在初始页面加载时设置为 false。当页面从缓存中加载时,它被设置为 true。
window.onpageshow = function(event)
if (event.persisted)
alert("From bfcache");
;
由于某种原因,jQuery 在事件中没有这个属性。不过,您可以从原始活动中找到它。
$(window).bind("pageshow", function(event)
if (event.originalEvent.persisted)
alert("From bfcache");
);
【讨论】:
感谢您提供 javascript 和 jquery 版本!你在最后错过了一个封闭的括号(这不是呻吟!)。我还要注意,为了其他人,IE 和 Chrome 报告 .persisted 始终是错误的,无论如何。 正如 Magnus 所指出的,在我删除 if 语句之前,这对我在 Chrome 中不起作用。 这适用于我在 Chrome 58.0.3029.110(64 位)和 FF 53.0.2(64 位)中没有任何更改。【参考方案4】:连接一个什么都不做的“onunload”事件:
<html><body>
<script type="text/javascript">
window.onload = function() alert('window.onload alert'); ;
window.onunload = function();
alert('inline alert');
</script>
<a href="1.html">Click Me!</a>
</body></html>
【讨论】:
不确定,我投了反对票,好像有人刚刚对这个问题的每个答案都投了反对票... 您应该添加到您的答案中,将 onunload 事件添加到您的页面实际上会禁用整个缓存的页面。这不仅会使 JS 再次运行,还会使服务器负载上升一个档次。这真的不是一个掉以轻心的建议,应该慎重考虑。 @dreagan,这会禁用 bfcache,但不一定禁用 HTTP 缓存。 HTTP 缓存有另外一套规则。如果你在那里抛出一个服务器端睡眠,你应该在点击返回时注意到它。 Mozilla 在FAQ for BFCache 的第三个问题中谈到了这一点。 我说的是 BFcache,应该指定的。这并不意味着您应该在不通知 OP 后果的情况下提出这样的建议。另一种方法是使用 onpopstate 事件再次尝试触发 javascript。 我仍然不知道我是否理解。如果客户端的本地 bfcache 被绕过,为什么“服务器负载会上升一个档次”?是的,DOM 需要重建,但 HTML 应该是客户端 HTTP 缓存的一部分。是的,需要重新加载其他资源,但这些资源也应该是客户端 HTTP 缓存的一部分。至于onpopstate
,当这个问题在大约五年前被问到时,那个事件还是比较新的,browser support was very inconsistent【参考方案5】:
据我所知,Firefox 不会在后面触发 onLoad
事件。
它应该基于此链接here 触发 onFocus。
【讨论】:
经过测试,windows.onfocus 确实被调用了,即使没有设置空的 window.onunload 处理程序。设置 onunload 是一个更好的解决方法,但 .onfocus 也应该没问题。谢谢:)【参考方案6】:当用户使用浏览器历史导航返回页面时,使页面执行 JavaScript 的一种简单方法是 OnPopState 事件。我们使用它来暂停和重播主页 (https://fynydd.com) 上的视频。
window.onpopstate = function()
// Do stuff here...
;
【讨论】:
OP 不是询问带有哈希更改的单页应用程序,而是使用 history.back 直接导航回第一页。【参考方案7】:在我的情况下,window.onunload
带有一个空函数并没有帮助(当用户使用后退按钮时,我尝试为下拉菜单设置一个值)。并且window.onload
因其他原因不起作用 - 它被<body onload="...">
覆盖。
所以我使用 jQuery 进行了尝试,效果非常好:
$(window).on('pageshow', function() alert("I'm happy"); );
【讨论】:
【参考方案8】:对于某些情况,例如 ajax 操作,可以使用 url 更改侦听器
$(window).on('hashchange', function()
....
);
【讨论】:
以上是关于回到 Firefox 历史后,JavaScript 将无法运行的主要内容,如果未能解决你的问题,请参考以下文章