JavaScript - bfcache/pageshow事件 - event.persisted是否总是设置为false?

18
在一个标准的Java / SpringMVC / JSP / jQuery web应用程序中,我试图检测“返回”(或history.go(-1))事件,以便在我返回到页面时刷新(AJAX)摘要组件/面板的内容(我们可以更改由摘要组件显示的后端数据)。
我尝试了以下JavaScript代码(根据StackExchange上的一些帖子来实现此功能):
<script type="text/javascript">
$(document).ready(function() {
    window.onpageshow = function(event) {
        console.log("Event:");
        console.dir(event);
        if (event.persisted) {
            alert("non-jQuery - back to page - loaded from bfcache");
        } else {
            alert("non-jQuery - loaded page from server");
        }
    };
    $(window).on("pageshow", function(event){
        console.log("Event:");
        console.dir(event);
        if (event.originalEvent.persisted) {
            alert("jquery - back to page - loaded from bfcache");
        } else {
            alert("jquery - loaded page from server");
        }
    });
});
</script>

我正在使用OpenSUSE Linux,并尝试了FireFox和Chrome(最新版本),但每次事件的persisted属性被设置为false时(我可以在JavaScript控制台中看到这一点,并通过上面代码弹出的警报进行确认)。无论是从服务器加载还是通过“后退”按钮(或“返回”链接)再次显示,都是如此。

我的目的是,如果页面通过“后退”按钮或history.go(-1)调用显示,则使用AJAX调用从服务器重新加载摘要组件/面板以更新数据。

我还尝试设置一个不执行任何操作的卸载处理程序,以防止页面被放入bfcache中,但它似乎仍然显示bf-cached版本,并且event.persisted(或event.originalEvent.persisted)被设置为false

这个属性在Linux上被正确管理吗? 我的代码有什么问题吗? 任何帮助或想法将不胜感激,谢谢!


我认为这与Linux无关。我在运行OS 10.9 Mavericks的Mac上遇到了这个问题,使用的是Safari 7和Firefox 26。我尝试了所有我能找到的技术,包括让服务器发送缓存控制头(Cache-Control: no-cache, must-revalidate, max-age=0)。浏览器从未真正重新加载页面(通过Wireshark检查),而event.persisted始终为false。 - giskard22
3个回答

26
我发现隐藏的输入按钮不是一个可靠的解决方案,因为当用户返回页面并点击刷新时,它们可能会持有错误的值。一些浏览器(Firefox)在刷新时保留输入值,因此每次用户点击刷新时,它都会再次刷新,因为输入按钮持有错误的值。这是论坛的典型场景(用户查看主题,点击后退按钮返回到主题列表,并可能继续点击刷新以检查是否有新主题)。
正如Grégoire Clermont所指出的那样,event.persisted在Chrome(和IE)中存在问题,在截至2017年2月的任何一个浏览器中仍未修复。好消息是您可以依赖于chrome和IE的window.performance.navigation.type == 2。具有讽刺意味的是,Firefox对于后者不可靠,但这不应该有关系,因为它对于event.persisted是可靠的。以下代码对我有效:
if (document.addEventListener) {
    window.addEventListener('pageshow', function (event) {
        if (event.persisted || window.performance && 
            window.performance.navigation.type == 2) 
        {
            location.reload();
        }
    },
   false);
}

2022年更新:

由于window.performance.navigation.type已经废弃(参考:MDN),我已经更新了代码以实现同样的功能:

if (document.addEventListener) {
    window.addEventListener('pageshow', function (event) {
        if (event.persisted || performance.getEntriesByType("navigation")[0].type === 'back_forward') {
            location.reload();
        }
    },
    false);
}

自Firefox v70起,Firefox将正确支持window.performance.navigation.type = 2。 - Kelderic

9

这似乎是Chrome浏览器中的一个bug(在IE11中也存在)。

我找到了以下解决方法:

<input type="hidden" id="cacheTest"></input>
<script>
  var input = document.querySelector('#cacheTest')

  if (input.value === "") {
    // the page has been loaded from the server,
    // equivalent of persisted == false
  }
  else {
    // the page has been loaded from the cache,
    // equivalent of persisted == true
  }

  // change the input value so that we can detect
  // if the page is reloaded from cache later
  input.value = "some value"
</script>

这是利用大多数浏览器在从缓存加载页面时会保存表单字段值的事实来实现的。

尽管这适用于Chrome 39.0.2171.95(64位),但在iOS Chrome或Safari 8中似乎不能做到相同的效果。有什么建议吗?谢谢 - Pan Chrono
是的,实际上我通过使用history.popstate解决了这些问题,谢谢。 - Pan Chrono
@Pan,截至Chrome 39版本,这个功能是无法使用的。而且在Chrome 70版本中仍然无法使用。 - Kelderic

1

我知道有点晚了,但这对我有效:

window.onpageshow = function(e) {

    if (e.persisted) {

        alert("Page shown");
        window.location.reload();
    }
};

我认为你不需要在文档准备好的函数中使用它,只需像上面那样使用vanilla。


为什么被踩了?这是正确的方法,在Safari上测试过。 - edgarpetrauskas

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