最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
如何通过 window.onpagehide 与 onpageshow 精准捕捉移动端浏览器的冻结状态
时间:2026-06-15 09:35:52 编辑:袖梨 来源:一聚教程网
event.persisted === true 是页面状态需抢救的唯一可信信号;它在 pagehide 中标识 bfcache 或冻结,pageshow 中需校验该值及 localStorage 存在性才恢复,且仅同步可序列化字段。
pagehide 事件里 event.persisted 是唯一可信信号
移动端浏览器(尤其是 iOS Safari)在页面退到后台时,pagehide 会照常触发,但关键不是它“发生了”,而是 event.persisted 的值。只有当这个布尔值为 true 时,才表示浏览器打算保留页面状态——大概率走 bfcache 或冻结路径,而不是直接卸载。
常见错误现象:只监听 pagehide 就调用保存逻辑,结果在 Chrome Android 上重复触发(比如切到其他 App 又快速切回),或在 Safari 上漏掉冻结前的最后机会。
-
event.persisted === false说明页面即将销毁(如用户点关闭标签),此时保存无意义,甚至可能污染 localStorage -
event.persisted === true才是真正需要抢救状态的时刻;但要注意,它不保证后续一定能 resume,只是“尽力而为” - 别在
pagehide回调里读取element.scrollHeight或getBoundingClientRect()—— 页面已不可见,这些值常返回0
pageshow 的 event.persisted 必须校验,否则恢复逻辑会错乱
pageshow 确实会在页面从冻结或 bfcache 恢复时触发,但它也会在普通刷新后触发(此时 event.persisted === false)。如果你不加判断就执行恢复,用户刚刷新完表单,瞬间又被 localStorage 里的旧草稿覆盖。
正确做法是双条件检查:
- 必须满足
event.persisted === true - 且本地存储中确实存在对应键(比如
localStorage.getItem('uiState')不为null) - 恢复完成后,建议立即清除该键或加个已恢复标记(如
localStorage.removeItem('uiState')),避免下次pageshow再次误恢复
freeze + pagehide 组合才是防丢保底方案
freeze 事件理论上更贴近“冻结”动作本身,但它有严重兼容短板:iOS Safari 直到 16.4+ 才稳定支持,旧版本静默忽略;部分 Android WebView 根本不派发该事件。所以不能单靠它。
实操上必须组合使用:
- 先注册
freeze回调,在里面调用saveState()并设frozen = true - 再注册
pagehide,仅当event.persisted && !frozen时补存一次 - 加时间防抖:用
performance.now()记录上次保存时间,200ms 内不再写入,防止两个事件紧挨着触发导致冗余
恢复时不要重置整个页面状态,只同步可序列化字段
从冻结中 resume 或 pageshow 恢复时,DOM 和事件监听器都还在,只是 JS 执行暂停了。误以为要“重新初始化”会导致定时器重复启动、请求重复发送、UI 状态冲突。
真正该做的只有三件事:
- 滚动位置:用
window.scrollTo(0, saved.scrollY),别碰element.scrollTop(元素可能已被重建) - 表单字段:只设
input.value、textarea.value、select.selectedIndex这类原始属性 - 播放/编辑进度:如
video.currentTime = saved.time,前提是保存时没存 DOM 节点或函数引用
容易被忽略的是:保存内容必须纯 JSON 可序列化。存了 document.body 或 setTimeout 回调,JSON.stringify() 会静默丢掉字段,恢复时根本拿不到。
相关文章
- 伊莫星骑士支线任务如何完成 06-16
- 逆战未来深渊狂潮怎么玩 06-16
- 银河灰暗角落结局彩蛋触发方法分享 06-16
- 异能重组护盾流玩法攻略介绍说明 06-16
- 别拽了烤串师傅气味炸弹成就解锁攻略 06-16
- 银河灰暗角落暴击流玩法构筑分享 06-16