标签仅作语义容器,高亮需javascript遍历文本节点并安全替换;innerhtml.replace()易致xss、html结构错乱及标签破坏;须双重转义关键词、显式声明样式并适配深色模式与中文词边界。

mark 标签本身不实现搜索高亮,它只是语义容器;真正起作用的是 JavaScript 动态查找并包裹匹配文本的过程。直接写死 <mark>关键词</mark> 无法响应用户输入,也不安全。
为什么 innerHTML.replace() 是最危险的写法
很多代码一上来就用 element.innerHTML = element.innerHTML.replace(/keyword/g, '<mark>$&</mark>'),这会同时触发三类问题:
- XSS 风险:用户搜
<script>alert(1)</script>,拼进字符串后直接执行 - DOM 解析中断:关键词含
&、"、等字符,导致 HTML 结构错乱 - 破坏标签结构:在
<img src="logo.png">中搜logo,结果变成<img src="<mark>logo</mark>.png">,图片挂掉
根本原因是:你操作的是整个 HTML 字符串,而非纯文本内容。
必须只遍历和替换文本节点(NodeFilter.SHOW_TEXT)
安全高亮的核心是绕过字符串拼接,只处理真实文本内容:
- 用
document.createTreeWalker(element, NodeFilter.SHOW_TEXT, null, false)获取所有文本节点 - 对每个
node.textContent执行正则匹配,跳过空或全空白节点 - 关键词需双重转义:
escapeHtml(keyword)防 XSS,再用keyword.replace(/[.*+?^${}()|[]\]/g, '\$&')防正则报错 - 匹配后不用字符串拼接,而是
document.createElement('mark')→mark.textContent = matchedText→parentNode.replaceChild(mark, textNode)
这样能确保 <mark></mark> 只出现在文本流中,不侵入 HTML 标签内部。
样式必须显式声明,不能依赖浏览器默认值
浏览器默认的黄色背景(#ff0)在以下场景会彻底失效:
- 深色模式下对比度不足(
#ffeb3b在暗色背景上才达标) - Windows 高对比度模式强制重置所有未声明的
background-color - Safari 阅读模式剥离 UA 样式,
<mark></mark>变成无背景 - 邮件客户端或打印样式表中完全不可见
务必写死关键样式:mark { background-color: #ffeb3b; color: #212121; padding: 0.1em 0.3em; border-radius: 3px; },并补上暗色适配:@media (prefers-color-scheme: dark) { mark { background-color: #ffca28; color: #121212; } }。
中文搜索还要注意字词边界——比如搜“服务”,别把“服务器”“微服务”也切开高亮。可用 (? 模拟词边界,但别指望它替代分词。真正容易被忽略的点是:高亮后 <code>document.querySelector('mark') 返回 null,往往不是语法错,而是动态插入后 DOM 尚未重排、被其他逻辑覆盖、或目标在 Shadow DOM 里。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











