富文本编辑器草稿丢失主因是直接监听input事件立即存localStorage,导致中文输入法下存拼音碎片、丢失光标和选区;应采用防抖+去重、上下文隔离键名、DOM同步恢复及内容与状态分离存储。

直接监听 input 事件立刻存 localStorage,是富文本编辑器草稿丢失的主因——中文输入法下存的是拼音碎片,光标位置、折叠状态、选区信息全丢,刷新后内容还在,但交互完全失效。关键不是“要不要存”,而是“怎么存才真正可用”。
防抖 + 去重:避开输入法干扰和无效写入
中文输入过程中,一个字会触发十几次 input 事件(如“中国”→ “z” → “zh” → “zho”…),立刻存不仅卡顿,还污染草稿。必须加防抖:
- 用 setTimeout + clearTimeout 手写防抖,延迟 500–800ms 后再执行保存
- 每次新输入先清除上一个定时器,避免延迟堆积
- 只在 el.value !== lastSavedValue 时才调用
localStorage.setItem(),跳过无意义重复 - 对带
data-no-autosave属性或type="password"的字段自动跳过
上下文隔离:避免多页/多编辑器互相覆盖
共用同一键名(如 "draft")会导致不同页面、不同编辑框的内容相互覆盖。必须让键名具备唯一性:
- 推荐结构:
editor-content-${formId}(存文本)、editor-state-${formId}(存光标、折叠行等 UI 状态) - formId 可取自元素 id、URL 路径或哈希,例如:
editor-content-ide-main或editor-content-/post/edit/123 - 避免用
Date.now()生成临时键名——它不具稳定性,恢复时无法匹配
恢复时机与 DOM 同步:填完还得“告诉框架”
页面加载后草稿没出现?八成是 DOM 还没准备好就赋值,或者框架把刚填的值又清掉了:
立即学习“Java免费学习笔记(深入)”;
- 必须等 DOMContentLoaded 触发后再读取;Vue 用
mounted,React 用useEffect(() => {}, []) - 读取前做校验:
if (draft !== null && draft.trim() !== ""),防止 JSON.parse(null) 报错 - 对
<textarea>用el.value = draft,别用 innerHTML(有 XSS 风险) - 填完后手动派发事件:
el.dispatchEvent(new Event('input', { bubbles: true })),否则 Vue/React 的双向绑定不会响应
富文本混合内容:文本和状态必须分开存
localStorage 只能存字符串,但富文本编辑器的“状态”不是文本的一部分:
- 纯 HTML 字符串可存为
editor-content-xxx,但恢复时若用innerHTML = draft,所有事件监听器和动态状态都会丢失 - 光标位置、选区范围、折叠行号、错误标记等,需调用编辑器 API 单独提取(如 CodeMirror 的
getCursor()、Monaco 的getPosition()),序列化后存在editor-state-xxx - contenteditable 区域恢复时用
el.textContent = draft,禁用 innerHTML;预览区同理 - 不要存整个 outerHTML 或渲染后的 DOM 片段——那是冗余且不可靠的


















