textcontent + innerhtml 是最稳的前端转义方式,因浏览器原生 api 能准确复现 html 解析器行为,将原始字符串设为 textcontent 后读取 innerhtml,自动转成合法实体,避免手写正则漏转、误转或嵌套截断问题。

直接用 innerText + innerHTML 组合最稳,浏览器原生支持、不依赖正则、不漏字符、不 double-encode。
为什么不用手写正则替换 &、、<code>>?
手写正则看似简单,但顺序和覆盖范围极易出错:& 必须最先转,否则后续 会被误识别为 <code> 的一部分;<code>' 在属性值中是否要转,取决于你用单引号还是双引号包裹属性;正则若没加 g 标志,只替换第一个;遇到 & 这类已转义内容,还可能被二次转成 &。实际项目里,一个没注意就导致表格列数据截断或 title 属性提前闭合。
常见错误现象包括:
-
<td>5 & 10</td>渲染后变成5 10(&后内容被丢弃) -
<th title="User's input: <script>"></th>中的单引号未转,导致属性值在's处截断,<script></script>真的被执行 - 用
replace(/&/g, '&')处理过一次的字符串再进一遍函数,变成&
innerText → innerHTML 是最轻量可靠的方案
它利用浏览器自身解析逻辑,把任意字符串当纯文本塞进去,再读取其 HTML 序列化结果,天然规避所有手动映射遗漏和顺序问题。适用于所有现代浏览器环境,且代码极简。
实操建议:
- 创建临时
div元素:const temp = document.createElement('div') - 用
innerText写入原始字符串:temp.innerText = rawStr - 读取
innerHTML获取转义后结果:const escaped = temp.innerHTML - 无需清理 DOM,
temp是局部变量,离开作用域即释放
示例:escapeHtml('A&B "test"') → 'A&B "test"'
服务端或 Node.js 环境不能用 innerText 怎么办?
DOM API 在无浏览器环境不可用,此时必须回归显式映射,但要严格按顺序和完整集合处理。
关键点:
- 只转 5 个核心字符:
&、、<code>>、"、'—— 其他 Unicode 字符(如中文、emoji)不需要转,浏览器能直接显示 - 顺序固定:
&→→ <code>>→"→',用链式replace或单次正则 + 映射对象 - 避免
double_encode:检查输入是否已含&、等,可加一层预判逻辑,或设参数控制 - PHP 用户直接用
htmlspecialchars($str, ENT_QUOTES),比手写安全得多
编辑器里粘贴 HTML 源码时,别让转义干扰预览效果
很多富文本编辑器(如 CodeMirror、Monaco)本身不自动转义,用户复制一段 <div> 进去,若你后台又做一次转义,就变成 <code><div>,预览区显示的是源码文字而非结构。
正确做法:
- 区分「展示源码」和「渲染内容」两个通道:源码预览用
textContent或pre+code,不走innerHTML - 只有最终插入到页面 DOM 的地方才做转义(比如填进
td、title、data-*) - 从编辑器取值后,先判断用途:是存库、是发 API、还是直接 innerHTML?不同路径用不同策略
最容易被忽略的一点:前后端协作时,如果后端已返回转义后的字符串(如 "price & tax"),前端 JS 千万不要再调用 escapeHtml() —— 那会变成 "price & tax",页面显示 “price & tax”。











