不能用 innerHTML.replace() 高亮关键词,因其会破坏 HTML 结构、引发 XSS、导致 DOM 错乱或样式失效;必须用 TreeWalker 遍历文本节点,双重转义关键词并按长度降序处理多关键词。

直接用 innerHTML.replace() 动态高亮关键词,90% 的项目会在上线后出问题——不是 XSS 就是 DOM 错乱,或者高亮错位、样式消失。必须只操作文本节点,且关键词要双重转义。
为什么 innerHTML.replace() 一定不能用
它把整个 HTML 字符串当纯文本处理,完全无视标签结构:
- 用户搜
<script>alert(1)</script>→ 拼进字符串后直接执行 - 原文有
&、"、等字符 → 替换后 HTML 解析失败,页面白屏或布局撕裂 - 在
中搜
logo→ 变成,图片挂掉
- 关键词含正则元字符(如
[a-z])→new RegExp(keyword)报错中断
正确做法:只遍历文本节点 + TreeWalker
绕过字符串拼接,只动纯文本内容,用原生 DOM 方法插入 mark:
- 用
document.createTreeWalker(element, NodeFilter.SHOW_TEXT)获取所有文本节点 - 跳过空节点和全空白节点:
if (!node.textContent.trim()) return - 对每个
node.textContent执行匹配,不碰innerHTML - 关键词先正则转义:
keyword.replace(/[.*+?^${}()|[]]/g, '\$&') - 再创建节点:
const mark = document.createElement('mark'); mark.textContent = match; node.parentNode.replaceChild(mark, node)
多关键词高亮必须按长度降序处理
否则语义断裂、嵌套非法、读屏器播报混乱:
- 同时高亮
JavaScript和Script,若先匹配短词,会生成JavaScript,但原始结构是连续的 - 浏览器虽自动修正为两个独立
mark,但 CSS 样式错位、边界 padding 重叠、可访问性信息丢失 - 排序写法:
keywords.sort((a, b) => b.length - a.length) - 中文搜索需加 Unicode 边界断言:
/(?
mark 样式必须显式声明,不能依赖默认值
浏览器默认黄色背景在真实环境中基本不可用:
- Safari 阅读模式剥离 UA 样式,
mark变成无背景纯文本 - Windows 高对比度模式强制重置未声明的
background-color - 深色主题下默认
#ff0对比度仅 1.8:1,远低于 WCAG AA 要求(≥4.5:1) - 必须写死:
mark { background-color: #ffeb3b; color: #212121; padding: 0.1em 0.3em; border-radius: 3px; } - 补暗色适配:
@media (prefers-color-scheme: dark) { mark { background-color: #ffc107; color: #121212; } }
最易被忽略的是「光标位置维护」——replaceChild 会破坏原有文本节点,导致 getSelection() 失效;编辑器类场景必须在高亮前克隆选区,完成后主动恢复 Range,否则用户输入中途光标跳到开头。这不是锦上添花,而是可用性的底线。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











