直接加 contenteditable="true" 不足以实现稳定编辑,必须处理三件事:一是设置 white-space: pre-wrap 和 word-break: break-word 并统一焦点样式;二是组合监听 input、compositionend 和 blur 事件,辅以 MutationObserver;三是拦截 paste 事件,用 DOMParser 白名单过滤 HTML 或降级为纯文本插入。

直接加 contenteditable="true" 就能编辑?先看这三件事
不能只写 contenteditable="true" 就完事。浏览器默认行为会立刻暴露问题:Chrome 里空 <div> 点击不聚焦、Firefox 回删卡在末尾、Safari 按回车插 <div> 而不是换行——这些不是 bug,是规范行为。
实操建议:
立即学习“前端免费学习笔记(深入)”;
- 必须显式设置
white-space: pre-wrap和word-break: break-word,否则长文本折行错位、空格被折叠 - 加
outline: none去掉原生焦点框,再用box-shadow或边框模拟选中态,避免跨浏览器表现不一致 - 别给
<input>或<textarea>加这个属性——无效,且 Chrome/Safari 会静默忽略
input 事件监听内容变化为什么总丢数据
只监听 input 事件,等于主动放弃一半修改场景:右键粘贴、Ctrl+Z 撤销、中文输入法上屏、拖拽插入图片,全都不触发。
实操建议:
立即学习“前端免费学习笔记(深入)”;
- 组合监听:
input+compositionend(捕获中文输入完成) +blur(失焦兜底) - 关键节点必须用
MutationObserver监听childList和characterData,尤其当你允许插图、链接等富文本节点时 - 别在
input回调里直接读el.innerHTML——用户粘贴带<script>的 HTML 会执行脚本;优先用el.textContent或白名单清洗后的 HTML
粘贴 Word 或网页内容后样式崩塌、XSS 怎么防
用户 Ctrl+V 粘贴,常带 <font>、style、嵌套 <span>、甚至内联 width/height,轻则布局错乱,重则执行恶意脚本。
实操建议:
立即学习“前端免费学习笔记(深入)”;
- 拦截
paste事件,调用e.preventDefault(),再取e.clipboardData.getData('text/plain')走纯文本路径最稳 - 若需保留粗体/列表等简单格式,用
DOMParser解析'text/html',递归遍历只留<p>、<strong>、<ul>/<ol>/<li>,剔除所有style属性和未知标签 - 禁用
document.execCommand('insertHTML', ...)——它不校验,直接注入;改用document.execCommand('insertText', false, text)(虽已废弃,但目前兼容性最好)
React/Vue 动态渲染后光标消失、focus 失效怎么救
组件 re-render、v-html 更新、或手动插入节点后,浏览器常丢失光标位置,甚至把焦点重置到页面顶部——这不是框架问题,是 DOM 替换导致 selection 信息丢失。
实操建议:
立即学习“前端免费学习笔记(深入)”;
- 聚焦前手动保存:在
focus事件里用window.getSelection()记录range.startContainer和startOffset - 渲染完成后立即恢复:用
requestAnimationFrame延迟执行selection.addRange(range),避开 DOM 同步时机 - 移动端必须监听
compositionstart/compositionend,否则拼音输入上屏时内容丢失



















