系统无法监听页面被回收的瞬间,只能通过freeze和pagehide(persisted=true)事件在冻结前保存状态,并在pageshow中检测discard后重建时还原输入现场。

系统回收页面的“瞬间”本身无法被监听——discarded 状态没有对应事件,JS 执行环境已被彻底终止。所谓“监听回收瞬间”,实际是通过冻结前的最后时机保存 + 重新加载时的上下文识别,实现对用户输入现场的可靠还原。
真正能捕获的只有两个安全保存点
浏览器在丢弃页面前,最多给你两次同步执行机会:
- freeze 事件:页面即将进入 Frozen 状态,DOM 可读、定时器尚可清除、localStorage 可同步写入。这是最优先使用的保存入口。
- pagehide 且 event.persisted === true:说明浏览器计划缓存或冻结该页(而非正常卸载),此时若 freeze 未触发(如旧版 Safari),它就是兜底保障。
二者必须配合使用,并用标记防重:
let saved = false;const saveInputState = () => {
if (saved) return;
try {
localStorage.setItem('draft_form', JSON.stringify({
title: document.getElementById('title')?.value || '',
content: document.getElementById('content')?.value || '',
scrollY: window.scrollY
}));
saved = true;
} catch (e) { /* 忽略存储失败 */ }
};
window.addEventListener('freeze', saveInputState);
window.addEventListener('pagehide', e => {
if (e.persisted && !saved) saveInputState();
});
还原不是“恢复”,而是“冷启动重建”
用户切回被 discarded 的 Tab 时,页面是全新加载(navigation type 为 'navigate' 或 'reload'),pageshow 事件中 event.persisted === false 是关键信号。此时需主动判断是否属于 discard 后重建:
- 检查
localStorage中是否存在'draft_form'且时间戳距今 > 3 分钟(Frozen 通常撑不过 2–3 分钟,超时即大概率已 discard) - 避免在 pageshow 中立即 restore —— DOM 可能尚未就绪,建议用
requestIdleCallback或setTimeout(..., 0)延迟执行 - 还原后务必清除旧快照:
localStorage.removeItem('draft_form'),防止下次刷新误还原
输入控件还原要避开 DOM 引用陷阱
直接存 input 元素或 this.state 对象会失败,因为 discarded 后整个 JS 环境重置,所有引用失效。只存原始值:
- 表单字段:用
input.value、textarea.value、select.selectedIndex - 滚动位置:用
window.scrollX/window.scrollY,别存元素的scrollTop - 选中/勾选状态:用
checkbox.checked、radio.checked的布尔值 - 禁止序列化函数、DOM 节点、Date 对象(改用时间戳)、RegExp 等不可 JSON 化内容
移动端真机测试必须覆盖的关键场景
模拟器常漏掉真实回收路径,以下场景需手动验证:
- iOS Safari 锁屏后 2 分钟再唤醒 Tab
- Android Chrome 多任务切换 → 清理后台 → 切回网页
- 分屏模式下将网页拖至小窗并长时间闲置
- 低内存设备上同时打开 10+ 标签页后切回目标页
只要 freeze 和 pagehide(persisted=true) 都正确触发保存,pageshow 中完成条件判断与延迟还原,用户中断的输入就能自然接续,无需手动点击“恢复草稿”按钮。

















