onpagehide 不是 body 的合法属性,必须用 window.addEventListener("pagehide", handler) 监听,并通过 event.persisted 判断是否进入 bfcache 以决定保存或清理数据,iOS 需配合 freeze 事件兜底。

onpagehide 不是 body 标签的合法属性,也不能直接写在 HTML 里用作保存数据——它只能通过 JavaScript 监听,且必须配合 event.persisted 判断缓存状态,否则写入可能失效或被跳过。
onpagehide 事件不能写在 HTML 的 body 上
HTML 中不存在 onpagehide 这个内联属性(类似 onclick 那样),浏览器会忽略它。所有现代浏览器只支持通过 window.addEventListener("pagehide", ...) 注册该事件。
- 错误写法:
<body onpagehide="saveDraft()">—— 完全不触发 - 正确入口:必须用
window.addEventListener("pagehide", handler) - 注意:不要和 jQuery Mobile 的
pagehide混淆,那是框架私有事件,和原生无关
保存临时数据必须区分 persisted 状态
pagehide 触发时,event.persisted 是唯一可靠信号:为 true 表示页面将进入 bfcache(可安全保存),为 false 表示页面即将销毁(适合清理而非保存)。
-
if (e.persisted):此时调用sessionStorage.setItem()最稳妥,页面切回来时还能读到 -
if (!e.persisted):别再写新数据,应清空草稿(如sessionStorage.removeItem("draft")),避免残留脏数据 - 千万别在
!e.persisted分支里做异步保存(比如fetch()),此时 JS 执行窗口极短,大概率被中断
Safari 和 iOS 是最大兼容性陷阱
iOS Safari 对 pagehide 支持极不稳定:后台标签页冻结、锁屏、从其他 App 切入时,事件经常不触发,甚至监听了也根本不会执行回调。
立即学习“前端免费学习笔记(深入)”;
- 不能单独依赖它——必须和
freeze事件组合使用,freeze是 iOS 上更可靠的“最后执行时机” - 不要用
pagehide去读取getBoundingClientRect()或计算滚动位置,布局可能已失效,返回0 - 如果业务强依赖离线状态恢复,得加兜底:在
input和blur事件中实时存localStorage,pagehide只作补充
真正能落地的保存逻辑长这样
轻量、同步、带防重、有 fallback,不是“一锤子买卖”:
let saved = false;
window.addEventListener("pagehide", (e) => {
if (e.persisted && !saved) {
try {
sessionStorage.setItem("draft", JSON.stringify({ value: document.getElementById("myInput").value }));
saved = true;
} catch (err) {
// 忽略 QuotaExceededError 等异常,不中断流程
}
}
}, { once: true });
// 同时监听 freeze(iOS 关键兜底)
window.addEventListener("freeze", () => {
if (!saved) {
sessionStorage.setItem("draft", JSON.stringify({ value: document.getElementById("myInput").value }));
}
}, { once: true });
复杂点不在语法,而在时机判断和平台差异——persisted 是开关,freeze 是保险,而真实用户输入,永远要靠 input 事件提前捕获。



















