应优先使用 textContent 更新纯文本,仅在需浏览器解析 HTML 标签时才用 innerHTML;处理不可信富文本须用 DOMPurify 等白名单方案净化,禁用 innerText 作安全兜底。
用 innerHTML 修改结构、用 textContent 更新纯文本,是两种根本不同的操作——选错不仅有安全风险,还会破坏交互或性能。关键不是“怎么写”,而是“为什么这么选”。
只有当你需要浏览器真正解析并渲染 HTML 标签时,才用 innerHTML。比如插入加粗、链接、换行、列表等带语义的富文本。
el.innerHTML = "请检查 <strong>邮箱格式</strong> 并重试"
box.innerHTML = "<h2>欢迎页</h2><p>点击开始</p>")⚠️ 只要字符串里拼接了任何外部数据(用户输入、URL 参数、API 返回值),就立刻进入高危区——<img onerror="alert(1)"> 这类代码会被执行。
立即学习“前端免费学习笔记(深入)”;
90% 的文本更新场景,你其实只需要显示一段文字,不希望它被当 HTML 解析。这时候 textContent 不仅安全,还更快、更稳定。
errorEl.textContent = "密码不能少于6位" —— 即使用户输入了 <script>fetch('/steal')</script>,也只当普通字符显示它不会清空子节点,不触发重排,不丢失事件监听器,也不重置 input 的 value 值——这些是 innerHTML 做不到的。
正则匹配 <script> 或删掉 onclick 属性,几乎必然被绕过。真实攻击常藏在 onanimationstart、href="javascript:"、SVG 事件里。
el.innerHTML = DOMPurify.sanitize(dirtyHtml, {ALLOWED_TAGS: ['b','i','br'], ALLOWED_ATTR: ['class']})
sanitize-html),前端只负责渲染,责任分离更可靠contenteditable + 自研编辑器控制输出innerText 看起来像 textContent,但它受 CSS 影响(display: none 的文字不计入)、会自动折叠空白、在表格中行为异常,还会强制触发重排——这不是“稍弱一点的安全选项”,而是逻辑上就不该用于防 XSS。
el.textContent !== undefined ? el.textContent = txt : el.innerText = txt