<mark>标签仅负责语义标记和默认样式渲染,不自动匹配关键词;需手动用正则转义搜索词、全局忽略大小写匹配,并安全替换为<mark>包裹内容,避免DOM污染与XSS风险。

mark 标签在搜索结果高亮中的实际作用
<mark> 本身只是语义化标签,浏览器默认用黄色背景渲染,但它**不会自动匹配或高亮关键词**。你得自己把搜索词从文本里找出来,再用 <mark> 包裹——它不负责“搜索”,只负责“标记”。
如何安全地用 JavaScript 替换并包裹关键词
直接用 String.prototype.replace() 容易出问题:大小写不敏感时漏匹配、正则特殊字符(如 .、?、()会崩、多次替换嵌套导致标签错乱。
- 先对搜索词做正则转义:
searchTerm.replace(/[.*+?^${}()|[]\]/g, '\$&') - 用
g和i标志确保全局+忽略大小写:new RegExp(escapedTerm, 'gi') - 替换时用函数捕获匹配内容,避免重复包裹:
text.replace(regex, match => <mark>${match}</mark>) - 如果目标文本是 HTML 字符串(比如含已有标签),先提取纯文本再操作,否则可能污染结构
为什么不能直接 innerHTML += <mark>...
用 innerHTML 拼接或重赋值会触发 DOM 重建,丢失事件监听、表单状态、焦点位置。尤其在搜索框实时高亮时,输入框可能突然失焦。
- 优先用
textContent提取原始文本,处理后塞进innerText或用DocumentFragment构建新节点 - 若必须操作 HTML 内容,用
DOMPurify.sanitize()过滤后再插入,防止 XSS(比如用户搜<img src=x onerror=alert(1)>) - 对长列表逐项高亮时,加
requestIdleCallback控制节奏,避免卡顿
服务端返回已高亮的 HTML 是否更稳妥?
是,但要注意边界:后端模板(如 Django 的 |highlight)或 API 返回带 <mark> 的字段,省去前端解析负担。不过得确认:
立即学习“前端免费学习笔记(深入)”;
- 服务端是否做了正则转义和 HTML 实体编码(防止
&变成&) - 响应头是否设了
Content-Type: text/html; charset=utf-8,否则中文可能乱码 - 前端拿到后仍要用
innerHTML插入,就得信任该字段——若来源不可控,必须过一遍DOMPurify
最麻烦的其实是多音字、词干匹配、标点粘连(比如搜“Python”却想高亮“Python3”里的“Python”),这些 <mark> 压根不管,得靠分词库或正则边界符 配合处理。



















