应使用 DOMParser 解析 HTML 后清洗,而非正则;必须删除危险标签和事件属性,保留语义结构;需单独处理零宽字符和剪贴板污染;清洗策略须可配置、可绕过、可审计。

直接删 style 属性比正则安全,但仅删 style 不够——富文本粘贴进来的 HTML 还带着 onerror、data-*、align、零宽字符、 和嵌套 <font></font> 标签,这些都会污染 DOM 结构、干扰 CSS 选择器、破坏 SSR 一致性,甚至引发 XSS 风险。
为什么不能用 innerHTML.replace(/]*>/g, "") 清标签
这个正则看着快,实际踩坑极多:
- 匹配不到注释
<!-- -->、CDATA 段、自闭合标签里的换行或引号(比如<img src="a>b.jpg" alt="HTML怎么清理富文本转码引入的垃圾属性" >) - 会把
<script>console.log("x>y")</script>中的>当作标签结尾,直接截断 JS - 删完只剩扁平文本,丢失
<p></p>、<ul></ul>、<blockquote></blockquote>等语义结构 - 对属性值里含
>或转义符(如")完全无感,极易漏删或错删
DOMParser + querySelectorAll 是唯一靠谱起点
必须先把字符串走标准解析路径,否则所有清洗都是空中楼阁:
- 用
new DOMParser().parseFromString(html, "text/html")得到文档对象,不操作原始 DOM - 查所有带危险属性的节点:
doc.querySelectorAll('*[onerror], *[onload], *[onclick], script, style, iframe, object') - 遍历用
for (const el of nodeList),不用forEach——DOM 变更时 NodeList 是活的,forEach会跳过动态插入/删除的节点 - 删
style用el.removeAttribute("style"),别用setAttribute("style", "")——空style属性仍会被[style]选择器命中
该留什么、该砍什么得按语义分级
不是“越干净越好”,而是保留可读性与结构信息:
立即学习“前端免费学习笔记(深入)”;
- 必须删除:
<script></script>、<style></style>、<iframe></iframe>、<object></object>、所有含on\w+的标签(如<div onclick="alert(1)">)<li>建议删除:<code><font></font>、<u></u>、<strike></strike>、<span></span>(除非它有白名单class,比如highlight) - 应保留:
<p></p>、<h1>–<h6></h6> </h1>、<ul>/</ul> <ol>/<li> </ol>、<blockquote></blockquote>、<img alt="HTML怎么清理富文本转码引入的垃圾属性" >(但需清理width/height,只留src和alt) -
style属性只放行白名单:text-align、margin-top/margin-bottom、max-width(仅限<img alt="HTML怎么清理富文本转码引入的垃圾属性" >) - 不要等它进 DOM 再清理——在
paste事件里就调event.preventDefault(),然后读event.clipboardData.getData("text/plain")而非"text/html" - 如果已污染,清空系统剪贴板:Windows 下执行
echo off | clip,macOS 下用printf "" | pbcopy - 后续文本处理加一层
.replace(/[\u200b-\u200f\u202a-\u202f\ufeff]/g, ""),别依赖trim()
零宽字符和剪贴板污染必须单独处理
Firefox/Edge 粘贴时带 \u200b、\u200c、\ufeff 是常态,它们不显示,但会卡住 textContent.trim()、让正则失效、导致移动端排版错乱:
真正难的不是删多少,而是判断哪些“脏”是业务需要的——比如微信公众号复制的 <section class="qqmusic"></section>,删了就丢音频;又比如某些编辑器靠 data-id 维护内容锚点,一并清掉会导致协作崩溃。清洗逻辑必须可配置、可绕过、可审计,而不是写死成“一刀切”。



















