如何在使用浏览器返回按钮时强制重新加载页面?

188

我需要以某种方式检测到用户按了浏览器的后退按钮,并使用jquery重新加载页面以进行刷新(重新加载内容和CSS)。

如何通过jquery检测这样的操作?

因为现在如果我使用浏览器的后退按钮,一些元素不会被重新加载。但是,如果我使用网站中的链接,所有内容都会刷新并正确显示。

重要!

有些人可能误解了我的意思。我不想刷新当前页面。我想刷新在按下后退按钮后加载的页面。以下是更详细的说明:

  1. 用户正在访问页面1。
  2. 当在页面1上时 - 他单击链接以进入页面2。
  3. 他被重定向到页面2。
  4. 现在(重要部分!)他单击浏览器的后退按钮,因为他想返回到页面1
  5. 他回到了页面1 - 现在页面1正在重新加载,并提示类似“您已回来!”的信息。

不要试图篡改正常用户行为,为什么不尝试理解为什么你的代码在页面加载时无法工作,需要重新加载页面呢? - Lelio Faieta
6
@LelioFaieta,我更改了类别以显示更改。 如果用户单击某个内容,数据库中的值将通过ajax更改。 当ajax完成时,例如从 on 更改为 off,css类别也会更改。它已经保存在数据库中,用户可以正确地看到所有内容。现在他点击其他链接。 例如关于我们页面,对吗? 现在,他在关于我们页面上。 然后他决定返回先前的页面,并单击浏览器的后退按钮。 当他回到页面时,由于浏览器缓存,他看到的更改是在他触发ajax(开/关类别)之前显示的页面。 - John Doeherskij
1
你的 Ajax 调用是使用 get 还是 post 方法? - Lelio Faieta
2
@LelioFaieta 第二部分.. 我还使用了数据属性,但没有效果。如果页面重新加载,一切都会很好。如果我在该页面上按F5,则通过ajax更改的值将显示出来。我认为这是某种与浏览器缓存相关的问题,当css/html部分没有完全重新加载时。只有在按下f5后才会重新加载。 - John Doeherskij
@LelioFaieta $.ajax({ url: url, method: 'post', processData: false, contentType: false, cache: false, dataType: 'json', data: formData, }) 你认为这可以通过ajax实现吗?如果是这样就太好了。 - John Doeherskij
18个回答

165
你可以使用pageshow事件来处理浏览器通过历史记录遍历到您的页面的情况:
window.addEventListener( "pageshow", function ( event ) {
  var historyTraversal = event.persisted || 
                         ( typeof window.performance != "undefined" && 
                              window.performance.navigation.type === 2 );
  if ( historyTraversal ) {
    // Handle page restore.
    window.location.reload();
  }
});

请注意,HTTP缓存也可能涉及其中。您需要在服务器上设置适当的与缓存相关的HTTP标头,以仅缓存需要被缓存的资源。您还可以强制重新加载以指示浏览器忽略HTTP缓存:window.location.reload( true )。但我认为这不是最佳解决方案。
有关更多信息,请查看:

你能帮助用户Dhiraj吗?他的代码已经走在正确的轨道上,但是它会重新加载两次。顺便说一下,我已经尝试过window.addEventListener( "unload", function() {} );,但是它没有任何作用,返回按钮仍然像以前一样工作,没有任何变化 ;( - John Doeherskij
如何卸载BFCache?能否用更具体的信息更新您的代码?这行window.addEventListener( "unload", function() {} );不起作用。它是否完整? - John Doeherskij
1
我仍然看到双重加载 ;( 一旦默认的Firefox(显示旧页面; 可能来自浏览器缓存?)然后脚本再次启动。脚本将重新加载到实际的阶段,但我仍然会看到旧状态大约一秒钟 ;( 我已经将代码放在 $(document).ready( function() { /* code here */ }); 中。 - John Doeherskij
11
window.performance.navigation is deprecated. To check the navigation type I used window.performance.getEntriesByType("navigation")[0].type === "back_forward" - secondbreakfast
3
不适用于Chrome(09/2022,Chrome 105.0):window.performance.getEntriesByType("navigation")[0].type可以告诉我们页面在点击链接和返回按钮之前是如何被初始加载的。如果我先导航到该页面,然后导航到另一个页面,再返回,那么我会得到type="navigate"。如果我重新加载页面,然后点击链接,再返回,那么我会得到type="reload"。我从来没有像其他任何好的浏览器一样得到过"back_forward"。这在FFox或Edge中完美运行。有人能帮我解决Chrome的问题吗?还是需要一个新的问题? - fpierrat
显示剩余5条评论

84

这篇文章发布有一段时间了,但如果您不需要支持旧的浏览器,我发现了一种更加优雅的解决方案。

您可以使用以下代码进行检查:

performance.navigation.type

文档,包括浏览器支持信息,请参见:https://developer.mozilla.org/en-US/docs/Web/API/Performance/navigation

因此,要查看页面是否是使用“后退”从历史记录加载的,可以执行以下操作:

if(performance.navigation.type == 2){
   location.reload(true);
}

数字2表示页面是通过浏览历史记录访问的。其他可能性包括-

0:页面通过链接、书签、表单提交或脚本访问,或者通过在地址栏中输入网址访问。

1:页面通过点击“重新加载”按钮或使用Location.reload()方法访问。

255: 其他方式。

这些详细信息在这里:https://developer.mozilla.org/zh-CN/docs/Web/API/PerformanceNavigation


请注意,Performance.navigation.type现已过时,应改用PerformanceNavigationTiming.type,它返回'navigate'/'reload'/'back_forward'/'prerender':https://developer.mozilla.org/zh-CN/docs/Web/API/PerformanceNavigationTiming/type


3
这个检查对我很有效。那个2具体是什么意思? - RitchieD
这个很好用..我把它放在最顶部..页面重新加载时没有加载任何其他脚本。 - NMathur
这个很好用。真是太棒了... 它非常快速和可靠,不像其他答案那样慢。谢谢。 - Jithin Raj P R
1
这个在Chrome浏览器上可以工作,但在Firefox上不能。 - praaveen V R
17
这已过时(参见https://w3c.github.io/navigation-timing/#obsolete)。 - David Vielhuber
在最新的Chrome 79.0.3945.117中对我有效。 - Avatar

52

由于performance.navigation现在已被弃用,您可以尝试以下方法:

var perfEntries = performance.getEntriesByType("navigation");

if (perfEntries[0].type === "back_forward") {
    location.reload();
}

1
这是最新的答案。 - kvothe__
1
这段代码需要和上面Leonid的回答中的代码结合使用。 - gornvix
有人在iOS上测试过这个吗?我用performance.getEntriesByType("navigation")方法替换了旧的performance.navigation.type方法,结果我的页面上所有JS都在iOS上停止工作了。 - Ben in CA
其他可能的值包括reloadnavigate:https://developer.mozilla.org/en-US/docs/Web/API/PerformanceNavigationTiming/type - run_the_race
1
@BeninCA 我已经在iOS上尝试过了。它不会破坏页面上的其他js,但也不能强制重新加载以进行后退按钮导航。 - Les Nightingill
显示剩余6条评论

36
jQuery( document ).ready(function( $ ) {
    
   //Use this inside your document ready jQuery 
   $(window).on('popstate', function() {
       location.reload(true);
   });
    
 });

当用户点击回退或前进按钮,或者使用ajax时,此功能将100%起作用。

如果不起作用,则脚本的其他部分可能存在配置错误。

例如:如果之前的页面设置状态为:

重新加载页面,则可能会出现此问题。

window.history.pushState('', null, './');`

因此,当你使用 history.pushState(); 时, 确保你正确地使用它

在大多数情况下,你将会使用:

history.pushState(url, '', url); 

不是window.history... 确保url已定义。


这在IE中不起作用。https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/3740423/ - RitchieD
@RitchieD - 截至今天,在Windows 10上,这在IE11上运行良好。注意:我没有使用EDGE。 - Dan G
1
我会从重新加载中删除“true”,以使用HTTP缓存。对于大多数情况,重新加载资产是没有意义的。 - konyak

13
我尝试了之前回答中的所有解决方案,但都没有起作用。
最后,我找到了这个解决方案,它确实起作用:
(function () {
    window.onpageshow = function(event) {
        if (event.persisted) {
            window.location.reload();
        }
    };
})();

3
从顶部答案到底部,第一个实际起作用的。谢谢。 - stats con chris

13

对我解决问题的另一种方案是禁用页面缓存。这会使浏览器从服务器获取页面,而不是使用缓存版本:

Response.AppendHeader("Cache-Control","no-cache, no-store, must-revalidate");
Response.AppendHeader("Pragma", "no-cache");
Response.AppendHeader("Expires", "0");

最佳解决方案,但这是我使用的版本。 Response.Cache.SetCacheability(HttpCacheability.NoCache); Response.Cache.SetMaxAge(TimeSpan.Zero); Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches); Response.Cache.SetNoStore(); - zeal
2
这看起来像是一个服务器端命令。这是用哪种语言编写的? - Eric McWinNEr
1
至少对于Firefox浏览器而言,“no-store”有所不同。 - claasz
在ASP.NET Core 3.1中,您可以在控制器操作上使用属性:[ResponseCache(Location = ResponseCacheLocation.None,NoStore = true)],来自https://dev59.com/vZbfa4cB1Zd3GeqPtWtw。 - AGB

9

如果用户点击返回按钮,目前最新的重新加载页面的方法如下:

const [entry] = performance.getEntriesByType("navigation");

// Show it in a nice table in the developer console
console.table(entry.toJSON());

if (entry["type"] === "back_forward")
    location.reload();

请查看这里获取来源。


有人在iOS上测试过这个吗?我用performance.getEntriesByType("navigation")方法替换了旧的performance.navigation.type方法,结果我的页面上所有JS都在iOS上停止工作了。 - Ben in CA
在Chrome中无法工作。没有尝试过Safari。 - MeSo2

7
您应该使用一个值为“no”的隐藏输入作为刷新指示器:
<input type="hidden" id="refresh" value="no">

现在使用jQuery,您可以检查其值:
$(document).ready(function(e) {
    var $input = $('#refresh');

    $input.val() == 'yes' ? location.reload(true) : $input.val('yes');
});

当您单击返回按钮时,隐藏字段中的值将保留与最初离开页面时相同的值。
因此,第一次加载页面时,输入框的值将为“否”。当您返回该页面时,它将是“是”,您的JavaScript代码将触发刷新。

2
它不起作用。我已经尝试了Firefox和Chrome,但它仍然无法工作。 - John Doeherskij
是的,我确实误解了。感谢您详细更新问题。 - Dhiraj
现在它可以工作了。但是它重新加载了两次,看起来有点奇怪。第一次重新加载时,什么也没有发生 - 这可能是默认的浏览器行为。第二次重新加载时 - 通过您的脚本 - 值被刷新了,但是它看起来很糟糕,因为它重新加载了两次。有什么想法可以改进一下,使重新加载看起来更好或只重新加载一次?在Chrome中看起来比Firefox好,重新加载更快,但我仍然会看到原始的后退状态(大约一秒钟或半秒钟),而脚本重新加载只会在此之后进行。 - John Doeherskij
有没有新想法可以修复“双重加载”问题? - John Doeherskij
@JohnDoeherskij 我已经在下面添加了一个解决方案作为答案,可以在Safari中使用。 - paulo77
显示剩余2条评论

4

适用于大多数浏览器的JS解决方案

本页面中的其他许多方法都无法解决我的问题,可能是因为"bfcache"在用户返回页面时阻止了任何操作。但是,我发现在大多数浏览器中注册一个window.onbeforeunload处理程序对我有用,我认为这有效是因为它隐式地使"bfcache"失效。以下是代码:

window.onbeforeunload = function() {
  window.location.reload(true);
}

这个事件可能会在其他情况下触发,而不仅仅是“返回”按钮导航,但在我的情况下,这并不重要。我在2021年8月的以下平台上测试过最新版本的浏览器:

  • Linux:在Chrome和Firefox中可运行。
  • Android:在Chrome、Firefox和Opera中可运行。
  • OS X:在Chrome和Safari中可运行。
  • iOS:在Safari中无法运行

在我的情况下,我并不太关心移动端。我确实关心IE,但没有访问IE的权限,所以我无法测试它。 如果有人在IE上尝试并能在评论中报告结果,那将非常有帮助。

服务器端响应头可以修复iOS Safari的问题

我发现,如果使用Cache-Control响应头使浏览器缓存失效,iOS Safari也可以正常工作。即发送

Cache-Control: no-store, must-revalidate

修复 iOS Safari。请参考this SO answer以了解如何在各个平台上设置Cache-Control响应头。

3

这在最新的Firefox和Chrome中都可以使用,截至2021年11月。

    window.addEventListener( "pageshow", function ( event ) {
     var perfEntries = performance.getEntriesByType("navigation");
     if (perfEntries[0].type === "back_forward") {
       location.reload();
     }
    });

这种监听'pageshow'事件然后检查PerformanceNavigationTiming条目中是否有'back_forward'条目的组合对我来说有效,而其他建议则无效。 - geogeo

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