不能用 innerHTML.replace() 直接处理整个 HTML 字符串,否则 DOM 会崩、事件丢失、XSS 风险高;必须只操作 Node.TEXT_NODE,用 mark 标签包裹匹配文本。

不能用 innerHTML.replace() 直接处理整个 HTML 字符串,否则 DOM 会崩、事件丢失、XSS 风险高;必须只操作 Node.TEXT_NODE,用 mark 标签包裹匹配文本。
为什么 innerHTML.replace() 一用就出问题
用户输入 cat[0] 或 <script></script>,正则直接报错或执行脚本;搜 p 可能把 解析成 p>,HTML 结构非法;原始文本若在 React Native 中,替换后 被切开,样式和语义全丢。
- 所有匹配必须限定在纯文本节点内,跳过
Element、Comment、Script节点 -
textContent是唯一安全提取人类可读文本的方式(innerText会吞掉display: none内容,但保留换行,位置计算不准) - 关键词含
.、*、[等正则元字符时,必须先转义:keyword.replace(/[.*+?^${}()|[]]/g, '\$&')
用 TreeWalker 安全遍历并高亮文本节点
这是原生、零依赖、IE9+ 兼容的方案,只让正则接触真正该匹配的文本内容。
- 创建遍历器:
const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, null, false) - 循环中过滤空节点:
if (!node.textContent.trim()) continue - 构造正则时加
gi标志:new RegExp(escapedKeyword, 'gi') - 匹配后不用字符串拼接,而是创建
mark元素:const mark = document.createElement('mark'); mark.textContent = matchedText - 用
node.parentNode.replaceChild(mark, node)替换,并调用node.parentNode.normalize()合并相邻文本节点,防止重复高亮
中文模糊匹配要防“字词边界误匹配”
搜“服务”,不希望“服务器”“微服务”整词被高亮——因为中文无空格,/服务/gi 会子串匹配。简单有效的方式是用 Unicode 边界断言模拟词边界:
生成可在 deepbi 沙箱 iframe 内运行或作为独立文件运行的交互式 HTML 页面,使用 `window.deepbi` JS SDK 实现数据查询、空间管理、文件浏览及用户操作。当用户提出以下需求时启用该能力: - 创建 KPI 仪表盘、数据表格、文件浏览器、成员列表、管理页面; - 明确要求“转成 dhtml”、“转译成 HTML”、“把 XX 页面转成……”、“控制台页面”、“管理后台”、“DeepBI 页面迁移”; - 提及位于 `apps/console/src/featur
- 正则写成:
/(? (? 是正向先行断言,(?=...)是正向后行断言,不消耗字符-
\u4e00-\u9fa5覆盖常用汉字,\s匹配空白,^/$处理开头结尾 - 注意:这不能替代分词,但对文档级搜索已足够,且无额外依赖
高亮后样式异常或可访问性失效怎么办
mark 是唯一语义正确、被屏幕阅读器识别、搜索引擎理解的高亮方式,不是视觉装饰。但它默认样式极弱,且容易被 CSS 重置掉。
- 浏览器 UA 样式可能被全局
mark { background: unset; }清空,必须显式覆盖:mark { background-color: #ffeb3b; color: #212121; } - 暗色模式下必须加媒体查询:
@media (prefers-color-scheme: dark) { mark { background-color: #ffc107; } } -
mark是内联元素,若父容器有white-space: pre-line或line-height异常,会导致背景撑开或文字截断,需强制重置:mark { display: inline; vertical-align: baseline; } - 别用
span+class替代 —— 语义缺失,读屏器不会播报“这是搜索命中”,SEO 也不识别
真正难的不是写出高亮逻辑,而是守住“只动文本节点”这条线:一旦跨出去碰 innerHTML 或跳过转义、边界、normalize,后续所有问题都会以 DOM 崩溃、XSS 漏洞、无障碍失败的形式反扑回来。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










