onpageshow 和 onpagehide 触发于页面生命周期变化(如切后台、锁屏、退至后台),非仅刷新;其中 onpageshow 的 event.persisted 可区分 bfcache 恢复(true)与页面重建(false),但无法单独判断是否为刷新,需结合 window.name 跨刷新持久特性识别真实刷新。

onpagehide 和 onpageshow 的触发边界在哪
这两个事件不是“页面刷新专用钩子”,而是浏览器对页面生命周期的通用通知机制。它们在多种场景下都会触发,比如:切到后台标签页、锁屏、APP退到后台、甚至安卓上按 Home 键——这些都不是刷新,但 onpageshow 仍会带 event.persisted === true。只有当页面被真正销毁后重建(如手动刷新、地址栏回车、F5),onpageshow 才会以 persisted: false 触发。所以单看 onpageshow 的 persisted 值,无法区分“冷启动”和“热恢复”。
window.name 是唯一能稳定标记“本次是否为刷新加载”的客户端手段
因为 window.name 在同源 tab 内跨刷新保持不变,且不依赖存储 API 或服务端配合,适合纯前端判断。关键点在于:必须在 onpageshow 中读取,而不是 onload 或 DOMContentLoaded,否则会漏掉从缓存恢复(bfcache)的场景。
-
onpageshow触发时,先检查window.name === 'refreshed' - 如果是,说明上次已标记过,本次就是刷新加载
- 如果不是,说明是首次加载或 bfcache 恢复,此时应设
window.name = 'refreshed'并记录初始状态 - 需在
onpagehide中清理?不用。保留它正是为了跨刷新识别
为什么 sessionStorage 不可靠
很多人用 sessionStorage.setItem('refreshed', '1') 配合 onpageshow 判断,但这是错的:sessionStorage 在 bfcache 恢复时依然存在,导致“首次加载”误判为“已刷新”。更糟的是,iOS Safari 对 bfcache 的行为不稳定,有时恢复时 sessionStorage 被清空,有时又保留——结果不可预测。而 window.name 不受 bfcache 影响,只要 tab 没关,值就一直在线。
真实移动端刷新检测代码模板
以下代码在 iOS 15+、Android Chrome 110+、微信 WebView 8.0.49+ 实测通过:
let isRefreshed = false;
window.addEventListener('pageshow', function(e) {
if (e.persisted) {
// 来自 bfcache 恢复,不是刷新
isRefreshed = window.name === 'refreshed';
} else {
// 页面重建:可能是刷新、F5、地址栏回车
isRefreshed = window.name === 'refreshed';
if (!isRefreshed) {
window.name = 'refreshed';
}
}
if (isRefreshed) {
console.log('检测到真实刷新');
// 执行刷新后逻辑,比如重置表单、清空临时状态
}
});
// 可选:onpagehide 中不做任何事,避免干扰 window.name
window.addEventListener('pagehide', function() {
// 不要在这里改 window.name,否则会破坏刷新识别链路
});
注意:不要在 pagehide 中重置 window.name,那是最常踩的坑——一旦重置,下次刷新就再也分不清了。











