不能直接用 innerHTML.replace() 替换关键词,因其会破坏 HTML 结构或执行脚本;安全做法是仅在文本节点中高亮,推荐用 TreeWalker 遍历 TEXT_NODE 并包裹 mark 标签。
不能直接替代,关键词本身是高亮的触发依据,不是可被替换的“内容”;强行用 innerHTML.replace() 替换关键词,极易破坏 HTML 结构或执行脚本。
innerHTML.replace() 会出事浏览器对 innerHTML 赋值时不做转义,直接解析字符串为 DOM。一旦关键词含 <、>、"、' 或 <script> 类片段,就会:
<img src="a.jpg"> 中的 a 高亮,变成 <img src="<mark>a</mark>.jpg">,属性值被截断)<script>alert(1)</script>,页面就弹窗)div,把 <div class="content"> 变成 <<mark>div</mark> class="content">,DOM 解析失败)核心思路是:只在文本节点中搜索,不碰任何 <...> 内容。可行路径有两条:
document.createTreeWalker() 遍历所有 Node.TEXT_NODE,逐个处理其 nodeValue,再用 document.createElement('mark') 包裹匹配段落/<[^>]*>/g),暂存后替换成占位符(如 [[TAG_0]]),再对纯文本部分做关键词替换,最后还原标签<img src="a<b.jpg"> 这类含 < 的属性值会导致正则失效——所以生产环境更推荐第一种 DOM 遍历法mark 标签不是万能的,得看场景<mark> 语义上表示“相关高亮”,浏览器默认带黄色背景,但它不解决根本问题:
立即学习“前端免费学习笔记(深入)”;
<mark>,且你又用字符串替换塞进新的 <mark>,就会嵌套错乱font-size、line-height 或 white-space 干扰,导致高亮块错位或换行异常<mark> 的默认样式支持较弱,建议显式加 mark { background: #ff0; color: #000; }
<mark> 需要 polyfill 或降级为 <span class="highlight">
用户输入的关键词不是拿来就用的字符串,必须清洗:
RegExp.escape()(或手写函数)转义正则特殊字符,否则搜 a.b 会被当成 “a任意字符b” 匹配textContent 或 innerText 提取原始文本时,要注意空格、换行、全角/半角差异(比如用户搜 “测试”,但页面里是 “测 试”(中文空格))String.prototype.match() 的 i 标志,但注意:DOM 文本节点里的大小写是原始的,别假设它和用户输入一致最易被忽略的一点:高亮操作本身会改变 DOM 结构,后续如果再次对同一区域调用高亮函数,<mark> 会被当作普通文本再次包裹——必须在执行前清除旧 <mark>,或记录已处理范围,避免重复渲染。