自动保存与防丢失是分层协作关系:前者解决“内容写到哪了”,后者解决“关页后能否找回”;需实时标记脏状态、定时落盘、服务端异步同步三者闭环,缺一不可。

自动保存和防丢失不是二选一,而是分层协作关系
自动保存解决的是「内容写到哪了」的问题,防丢失解决的是「关掉页面还能不能找回来」的问题。两者目标不同、触发时机不同、失效路径也不同——只做自动保存,用户清缓存或换设备就全丢;只做防丢失兜底(比如仅靠 beforeunload),一旦 JS 报错或浏览器崩溃,连最后快照都来不及写。
localStorage.setItem() 是自动保存的起点,但不是防丢失的终点
很多方案把 localStorage.setItem('draft', content) 当成防丢失完成标志,其实它只完成了第一跳:数据进了本地存储,但没校验是否真写成功,也没考虑多标签页覆盖、输入法组合过程误存、Safari 无痕模式直接抛 QuotaExceededError 等真实场景。
- 必须用
try/catch包裹localStorage.setItem(),iOS Safari 在无痕模式下会静默失败 - 键名建议带上下文,比如
draft-contact-form-20260411,避免多个表单互相覆盖 - 存之前比对新旧值,相同则跳过,减少无效 IO 和配额消耗
- 别存原始 DOM 或未序列化的对象,必须用
JSON.stringify(),否则读取时会报Unexpected token u in JSON at position 0
防丢失真正起效的三个关键动作必须提前做完
防丢失不是等用户要关页面才启动的抢救流程,而是由三件事组成闭环:实时标记脏状态、定时落盘、服务端异步同步。这三件事都得在 beforeunload 触发前完成,否则那个事件里什么都干不了。
- 用内存变量(如
window.__isFormDirty = true)记录是否改动,不要在beforeunload回调里读localStorage或算哈希 - 定时落盘用
debounce控制节奏(推荐 800ms),不是setInterval每 30 秒硬刷一次 - 服务端同步走轻量心跳(如聚焦时 POST
/api/draft/heartbeat),带etag校验,失败后降级提示并保留本地草稿
最常被绕过的环节:多端编辑冲突和状态可见性
用户在手机填了一半,又在电脑打开同一页面,两个 localStorage 同时写入,后保存者直接覆盖前者——这种问题不会报错,但数据就丢了。更隐蔽的是,界面不显示「已保存」「保存中…」「⚠️ 未同步」三种状态,用户根本不知道自己填的内容有没有真正落库。
- 右上角必须有实时状态标识,点击可手动重试,不能只靠后台静默提交
- 多端编辑需加版本号(如
draft_v2_202604111522)+ 时间戳,恢复时优先取最新版,冲突时给出合并提示而非静默覆盖 -
visibilitychange要监听标签页切走又切回,若期间服务端保存成功,就自动清除本地草稿,避免冗余
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











