800ms是当前最稳妥的防抖延迟值,既能适配中文输入法选词节奏避免存拼音碎片,又可防止用户关页丢稿;需手写settimeout+cleartimeout、内容比对、动态键名及dom就绪后恢复。

防抖延迟设多少才不丢内容又不卡顿
800ms 是当前最稳妥的平衡点。太短(如 200ms)挡不住中文输入法的“z”“zh”“zho”连发,存一堆拼音碎片;太长(如 1.5s)用户写完就关页,最后一段直接消失。
必须手写 setTimeout + clearTimeout,不能依赖 Lodash 的 debounce——它默认用 requestIdleCallback,在页面即将卸载时可能根本没机会执行。
- 每次新输入先
clearTimeout上一个定时器 - 仅当
el.value !== lastSavedValue才真正调用localStorage.setItem() - 跳过
type="password"、data-no-autosave字段,避免存敏感信息
键名怎么设计才能避免多页互相覆盖
用 editor-draft-${location.pathname}-${Date.now().toString(36)} 这类结构,比单纯 editor-draft 安全得多。同一域名下开 5 个编辑页,路径不同、时间戳不同,键名天然隔离。
如果页面带 ID(比如文章 ID 或表单 ID),优先用 editor-draft-${articleId},比路径更稳定——路径带查询参数时可能变化,ID 不变。
- 别用
Math.random()生成键名,不可靠且难调试 - 不要把整个 URL 当键名,特殊字符(如
?、&)需 encode,徒增风险 - 单页应用中,
location.pathname可能不变,得结合路由状态或组件 key 补充区分
DOM 加载后恢复草稿为什么还是填不进去
八成是元素还没挂载成功,或者框架接管了值绑定。直接在 DOMContentLoaded 里写 document.getElementById("editor").value = draft,在 Vue/React 里大概率被后续初始化覆盖。
正确做法:等 DOM 就绪 + 等框架就绪。Vue 用 mounted 钩子,React 用 useEffect(() => {}, []),且必须加存在性校验:
- 先检查
el && el.value !== undefined,再赋值 - 恢复后手动派发
input事件:el.dispatchEvent(new Event('input', { bubbles: true })),否则 v-model 或受控组件不响应 - 对空值做双校验:
if (draft !== null && draft.trim() !== ""),防止JSON.parse(null)报错
HTML/JS/CSS 混合内容恢复时为什么按钮失效、光标丢失
因为你只存了字符串,没管状态。把 innerHTML = storedHtml 插回去,所有事件监听器、光标位置、折叠行、语法高亮标记全部清零——这是最典型的“代码还在,交互全废”。
textarea 内容永远用 .value 赋值;contenteditable 区域用 .textContent,禁用 .innerHTML 防 XSS;预览区若需渲染 HTML,必须白名单过滤,不能原样插入。
- 光标、选区、折叠状态要单独序列化:CodeMirror 用
getCursor(),Monaco 用getPosition(),存进另一个 key(如editor-state-${id}) - 提交或离开前,记得清理草稿:
localStorage.removeItem(key),否则已发布的内容下次打开还会弹出来 - 兜底用
beforeunload:里面只做同步localStorage.setItem(),不加 await、不调封装函数、不尝试网络请求
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











