需约束浏览器默认行为:设white-space:pre-wrap、拦截enter键、初始化占位符、组合监听input/compositionend/blur事件、paste时转纯文本或白名单过滤html、手动保存恢复选区。

contenteditable="true"加了但光标乱跳、回车异常怎么办
直接写 contenteditable="true" 后出现光标卡住、按回车插入 <div> 或 <code><p></p>、删除空行后焦点丢失——这不是你代码写错了,是浏览器默认行为没被约束。
实操建议:
- 显式设置
white-space: pre-wrap和word-break: break-word,否则长文本换行错位、空格折叠 - 禁用默认聚焦轮廓:
outline: none,再用box-shadow模拟选中态,避免 Chrome/Firefox 表现不一致 - 拦截
Enter键:keydown中调用e.preventDefault(),再根据需求插入<br>或纯换行符(\n),别依赖浏览器自动换行 - 避免在空容器中触发编辑——父元素为空时,Safari 会吞掉焦点;可初始化时填一个
<span><br></span>占位
监听内容变化为什么 input 事件总漏触发
input 事件只对键盘输入敏感,粘贴、撤销(Ctrl+Z)、中文输入法上屏、拖拽插入、甚至部分 IME 提交都收不到。靠它存数据,必丢内容。
实操建议:
- 组合监听:
input+compositionend(捕获中文输入完成) +blur(兜底防失焦未保存) - 关键场景必须用
MutationObserver:监听characterData和childList变更,尤其当允许插图、链接等富文本节点时 - 别在
input回调里直接读el.innerHTML——用户粘贴带<script></script>的 HTML 会执行脚本;优先用el.textContent或白名单清洗后的 HTML
粘贴 Word 或网页内容后样式崩塌、XSS 风险怎么防
用户 Ctrl+V 粘贴,常带 <font></font>、style、嵌套 <span></span>、甚至内联 width/height,轻则布局错乱,重则执行恶意脚本。
实操建议:
- 拦截
paste事件,e.preventDefault()后取e.clipboardData.getData('text/plain')走纯文本路径最稳 - 若需保留粗体/列表等简单格式,用
DOMParser解析'text/html',递归遍历只留<p></p>、<strong></strong>、<ul></ul>/<ol></ol>/<li>,剔除所有style属性和未知标签 - 禁用
document.execCommand('insertHTML', ...)——它不校验,直接注入;改用document.execCommand('insertText', false, text)(虽已废弃,但目前兼容性最好) - 移动端必须监听
compositionstart/compositionend,否则拼音输入上屏时内容丢失
React/Vue 里动态渲染后光标消失、选区错位怎么救
框架重渲染 DOM、innerHTML 替换、或调用 execCommand 后,浏览器常丢失光标位置,甚至把光标重置到开头或空白处。
实操建议:
- 手动保存恢复选区:用
getSelection().getRangeAt(0)获取当前Range,在更新前序列化其startContainer、startOffset等,更新后再range.selectNodeContents()+sel.removeAllRanges()+sel.addRange(range) - 避免直接操作
innerHTML更新内容——改用textContent+ 增量 DOM 插入,减少结构扰动 - 在框架生命周期钩子(如 Vue 的
updated、React 的useEffect)里延迟恢复光标,确保 DOM 已就绪 - 不要嵌套多个
contenteditable元素——父子都设为 true 时,光标跳转和粘贴行为完全不可控











