直接调用 innerhtml.replace() 会出错,是因为 replace() 返回新字符串但不自动更新 dom,且若 keyword 含未转义正则元字符(如 [、*、.)或 html 特殊字符(如 &、),传入 new regexp(keyword) 会抛 syntaxerror,而 innerhtml = text.replace(...) 若未对 keyword 转义也必然失败。

为什么直接 innerHTML.replace() 会炸
用户输入 cat[0] 或 <script>alert(1)</script>,用 el.innerHTML = text.replace(keyword, '<mark>$&</mark>') 就会出事——不是“可能”,是必然。
- 正则元字符(
.、*、[等)未转义 →new RegExp(keyword)直接抛SyntaxError - HTML 特殊字符(
&、"、)未实体化 → 插入后破坏 DOM 结构,比如把 <code><code>console.log()变成<code>console.<mark>log</mark>(),<mark></mark>被撕开,解析中断 - 匹配发生在 HTML 字符串层级,而非文本内容层级 → 图片
<img src="logo.png">中搜logo,结果变成<img src="<mark>logo</mark>.png">,src值非法,图片挂掉
怎么只操作文本节点,不碰 HTML 结构
核心是绕过字符串拼接,用 TreeWalker 遍历纯文本节点,再用 DOM 方法组装 <mark></mark>。
- 用
document.createTreeWalker(element, NodeFilter.SHOW_TEXT)获取所有文本节点 - 跳过空节点:
if (!node.textContent.trim()) continue - 对每个
node.textContent执行匹配,但关键词必须双重转义:
— HTML 转义:keyword.replace(/[&"'`=/]/g, c => `${c.charCodeAt(0)};`)
— 正则转义:keyword.replace(/[.*+?^${}()|[]]/g, '\$&') - 构造正则时加
gi标志:new RegExp(`(${escaped})`, 'gi') - 匹配后不用字符串替换,而是创建节点:
const mark = document.createElement('mark');→mark.textContent = match;→node.replaceWith(mark);
mark 的样式为什么不能省略
浏览器默认黄色背景(#ff0)在真实场景中基本不可用:Safari 阅读模式剥离 UA 样式、Windows 高对比度强制重置 background-color、暗色主题下对比度低于 WCAG AA(#ff0 对深灰背景 ≈ 1.2:1)。
- 至少声明:
background-color、color、padding - 推荐组合:
mark { background-color: #ffeb3b; color: #212121; padding: 0.1em 0.25em; } - 深色模式必须手动适配:
@media (prefers-color-scheme: dark) { mark { background-color: #ffc107; color: #000; } } - 别写
background: none—— 它不等于background-color: transparent,可能残留background-image
英文单词边界和中文匹配怎么处理
在中文里完全失效,而 cat 匹配到 education 是高频翻车点。
- 英文场景:用
new RegExp(`\b${escapedKeyword}\b`, 'gi')锚定单词边界 - 中文场景:
无效,需放弃正则全局匹配,改用String.prototype.indexOf()手动定位位置,再逐段切分插入<mark></mark> - 中英文混合文本:统一走
indexOf()+Text.splitText()方案,可控性更高,避免跨词误匹配 - 永远别用
replace(/keyword/g, '<mark>$&</mark>')—— 它不区分上下文,也不防嵌套断裂
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











