mark 是唯一语义正确、可访问且被搜索引擎识别的高亮方式;直接 innerhtml.replace() 会导致 xss、dom 损坏及结构错乱;安全做法须用 treewalker 遍历文本节点,结合 escapehtml、matchall 和 range.surroundcontents() 实现。

mark 是唯一语义正确、可访问、且被搜索引擎和屏幕阅读器识别的高亮方式。用 span 加 background-color 或内联 style 只是视觉模拟,不传达“这是搜索命中”的上下文意义。
为什么直接 innerHTML.replace() 会 XSS 和 DOM 损坏
用户输入 <script>alert(1)</script> 或 foo" onclick="alert(1) 时,字符串拼接进 innerHTML 会执行脚本或破坏结构。更隐蔽的问题是:原始文本节点可能跨多个 HTML 元素(比如 <strong>React</strong> Native),正则替换会切碎 DOM 树,导致样式错乱、事件丢失、甚至 Range.surroundContents() 报错 InvalidNodeTypeError。
安全做法必须走 DOM 节点操作:
- 用
document.createTreeWalker(root, NodeFilter.SHOW_TEXT, ...)遍历纯文本节点 - 对每个
Text节点调用node.textContent.matchAll(new RegExp(keyword, 'gi')) - 用
document.createElement('mark')创建新节点,再用range.surroundContents()或node.splitText()+parent.insertBefore()插入 - 匹配前先
escapeHtml(keyword),防止正则特殊字符(如.、[)被误解析
多词搜索 + 全词匹配怎么写正则
默认 new RegExp(keyword, 'gi') 是子串匹配,搜 node 会命中 frontend。要全词匹配,得加单词边界 \b;但注意 \b 在 JavaScript 字符串里需双反斜杠:new RegExp('\b' + escapedKeyword + '\b', 'gi')。
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
多词支持(空格分隔)不能简单 split(' '),要防连续空格和首尾空白:
- 用
input.trim().split(/\s+/).filter(Boolean)拆出有效关键词 - 每个词单独构造正则,全部命中才算匹配成功(
every()) - 若需“任一匹配即高亮”,改用
some(),但注意高亮逻辑要分别执行,避免重复包裹同一段文本
高亮后样式异常?检查这三处
mark 是内联元素,但它的父容器可能有 white-space: pre-line、display: flex 或 line-height 异常,导致换行错位或背景撑开。常见症状包括:高亮块宽度突变、文字被截断、相邻 mark 之间出现多余间隙。
- 强制重置
mark的盒模型:mark { display: inline; vertical-align: baseline; } - 显式声明
background-color和color,别依赖浏览器 UA 样式(Outlook、某些阅读模式会清空它) - 暗色模式下必须用
@media (prefers-color-scheme: dark)单独定义,否则黄色背景在深色底上不可读
真正容易被忽略的是:高亮操作后必须调用 element.normalize() 合并相邻文本节点——否则后续搜索会把已高亮过的 Text 节点再次拆分,造成嵌套 mark 或重复高亮。这不是可选优化,是 DOM 稳定性的前提。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










