直接设 contenteditable="true" 会崩样式,因为浏览器默认原样插入剪贴板的 text/html(含 Word 样式、微信 class、残留 script);必须拦截 paste 事件并 preventDefault,再用 DOMParser 安全提取文本结构,同时遍历 clipboardData.items 拦截图片。

粘贴富文本时为什么直接设 contenteditable="true" 就崩样式
因为浏览器默认把剪贴板里的 text/html 原样插入 DOM——Word 会带 style 和嵌套 span,微信复制可能含 class="rich-text",甚至残留 <script>。这不是 bug,是规范行为:contenteditable 只管“可编辑”,不管“怎么粘”。
常见错误现象:innerHTML 一读就执行脚本、段落塌成一行、光标卡在末尾无法回删、iOS 上粘贴后空白。
必须拦截 paste 事件并 preventDefault
不调用 event.preventDefault(),浏览器仍走默认插入逻辑,后续所有清洗都是马后炮。
实操建议:
立即学习“前端免费学习笔记(深入)”;
- 监听
paste事件,不是input或blur——它们触发时污染已发生 -
event.clipboardData.getData('text/plain')在 Safari 和部分旧 Android 上常为空,不能当唯一 fallback - 别信
innerText——它会丢换行;也别信正则/<[^>]*>/g——它删不掉注释、CDATA 或自闭合标签里的危险属性
安全提取纯文本且保留换行和缩进
核心不是“删 HTML”,而是“选对数据源 + 手动重建文本结构”。
实操建议:
立即学习“前端免费学习笔记(深入)”;
- 优先取
event.clipboardData.getData('text/html'),用DOMParser解析成文档片段,再遍历提取textContent,比纯文本更可靠 - 对每个
p、div(display: block)节点,手动补\n;对br插\n;对连续空格用.replace(/\s{2,}/g, ' ')后转空格 - 最后统一
.replace(/\u200b/g, '').replace(/\u00ad/g, '')清零宽字符,避免渲染异常
如何只放行文字、彻底拦截图片粘贴
监听 paste 时检查 event.clipboardData.items 是最稳方式。很多方案试图靠 CSS 或 dragover 拦截,实际完全无效——粘贴和拖拽是两套机制。
实操建议:
立即学习“前端免费学习笔记(深入)”;
- 遍历
event.clipboardData.items,对每个item.type.startsWith('image/')立即event.preventDefault() - Safari 旧版本不支持
items,fallback 到event.clipboardData.files.length > 0判断 - 即使拦住了图片,Chrome 有时还会把 base64 图片转成
<img src="data:image/png;base64,...">插入,需在setTimeout(() => { /* 扫描移除新 <img> */ }, 0)中处理
真正难的不是写几行过滤代码,而是意识到:粘贴行为在不同浏览器中根本不可预测——Safari 对 text/html 返回空、iOS 微信会注入不可见分隔符、Android 剪贴板管理器可能篡改 MIME 类型。你得为每种 fallback 准备校验逻辑,而不是指望一个解析路径通吃。



















