不能一输入就调用 localstorage.setitem(),因中文输入法下input事件高频触发会导致中间态覆盖、低端机静默失败、主线程卡顿,且safari隐私模式或部分安卓webview会限频拒绝写入而不报错。

为什么不能一输入就调用 localStorage.setItem()
中文输入法下,input 事件会高频触发(比如打“你好”,可能连续发出“n”“ni”“nih”“niha”“nihao”),直接存会导致中间态覆盖、低端机静默失败、主线程卡顿。Safari 隐私模式或某些安卓 WebView 甚至会限频拒绝写入,且不报错。
实操建议:
- 必须加防抖:用
setTimeout+clearTimeout延迟 800ms 再存,等用户停笔再落盘 - 存前比对内容是否真变了:
if (prevValue !== currentValue),避免无意义写入 - 跳过输入法组合中状态:
if (event.isComposing)时直接 return - 敏感字段如
type="password"、name="idCard"等,一律不存
键名怎么设才不会多个表单互相覆盖
硬写 'draft' 是线上最常见草稿消失原因——A 表单提交后,B 表单的输入直接把 A 的草稿冲掉。
实操建议:
- 键名必须带上下文标识,推荐格式:
`draft-${formId || 'default'}-${location.pathname}` - 若表单动态渲染(React/Vue 组件、AJAX 加载),
formId得从挂载后的 DOM 取,不能写死 - 时间戳可辅助去重,但别只靠它:
`draft-${formId}-${Date.now()}`适合单次草稿,多版本恢复需额外管理 - 对富文本编辑器(如
contenteditable),单独监听其input或用 MutationObserver,别混进普通表单逻辑
页面加载时怎么安全恢复草稿
很多代码在 DOMContentLoaded 里就遍历 form.elements 赋值,结果 DOM 还没出来,或者 Vue/React 组件根本没 mount,填了个寂寞。
实操建议:
- 等真正可用再操作:原生 JS 用
document.addEventListener('form-ready', ...),由表单渲染完成后再派发;框架中走mounted或useEffect - 填值前检查元素是否存在:
if (el && 'value' in el),checkbox/radio 单独处理el.checked = Boolean(data[el.name]) - 填完必须派发事件:
el.dispatchEvent(new Event('input', { bubbles: true })),否则v-model或受控组件不响应 - 只在编辑框初始为空时恢复:
if (!el.value && draftData) el.value = draftData,防止覆盖用户主动清空的操作
beforeunload 能不能用来保存草稿
不能。beforeunload 回调只有约 50ms 执行窗口,且必须同步返回字符串。里面塞 await saveDraft() 或 fetch() 全部失效,浏览器根本不等。
实操建议:
- 它唯一可靠用途是提示:“有未保存内容,确定离开?”——提前设标志位
let hasUnsavedChanges = false - 输入开始时设为
true,防抖保存成功后设为false - 不要在里面读写
localStorage,更别调异步函数 - 真正防丢靠的是防抖 + 时间戳校验 + DOM 就位后恢复,
beforeunload只是最后一道心理防线
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











