最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
index.html如何添加网页内的内容搜索高亮功能
时间:2026-06-28 10:00:46 编辑:袖梨 来源:一聚教程网
不能对 innerHTML 做正则替换,因为浏览器不自动转义 HTML 字符,关键词含 alert(1)、& 等会破坏标签结构,导致脚本执行、XSS 风险或 DOM 解析错误。
直接用 innerHTML 替换关键词高亮,90% 的情况下会出问题:表单值清空、事件监听器丢失、img 的 onerror 失效、甚至破坏嵌套结构。必须只操作文本节点。
为什么不能对 innerHTML 做正则替换
浏览器不会帮你转义 HTML 字符。如果用户搜 <script>alert(1)</script>,或者关键词里含 &、、<code>",innerHTML 会直接执行或解析成标签,轻则样式错乱,重则 XSS 风险。更隐蔽的问题是:一个带 onclick 的按钮,高亮后可能变成纯文本,点击失效;input 框里刚输的字也会被清空。
常见错误写法:
el.innerHTML = el.innerHTML.replace(/keyword/gi, '<mark>$&</mark>');
这种写法跳过了 DOM 树遍历,把整个 HTML 字符串当文本处理,完全无视了节点语义和状态。
立即学习“前端免费学习笔记(深入)”;
正确做法:只遍历并替换文本节点
核心逻辑是递归访问 DOM 节点,遇到 Node.TEXT_NODE 才做匹配和包裹,其余节点(元素、注释等)跳过。匹配时用 document.createElement('mark') 创建新节点,再用 replaceChild 替换原文本节点。
- 用
node.nodeType === Node.TEXT_NODE判断是否为文本节点 - 中文搜索需加 Unicode 边界限定,避免“窗透初晓”里搜“窗透”误匹配到“初晓”里的“透”字,正则建议写成
/(u4e00-u9fa5|^)s*keywords*(u4e00-u9fa5|$)/gi - 英文大小写不敏感匹配用
new RegExp(keyword, 'gi'),但注意keyword必须先escapeRegExp()防特殊字符 - 每次高亮前,先克隆当前选区(
getSelection().getRangeAt(0).cloneRange()),替换完再恢复,否则getSelection()返回空
highlightText 函数的关键参数与容错点
这个函数通常接收三个参数:node(要搜索的根节点)、keyword(用户输入)、caseSensitive(是否区分大小写)。但实际使用中容易忽略几个关键点:
-
keyword.trim() === ''时必须提前 return,否则正则变成//g,会匹配所有空字符串,页面炸开 - 若目标区域含大量动态内容(如 React/Vue 渲染区),不要直接传
document.body,应限定为具体容器,比如document.getElementById('content') - 多词搜索(如“AI 工具”)不能简单用
split(' '),要用keyword.split(/s+/).filter(Boolean),再逐个词调用高亮逻辑 - 性能敏感场景(如超过 200 条卡片),必须加防抖:用
setTimeout+clearTimeout控制触发频率,避免每敲一个字就重跑整棵树
CSS 和语义细节不能省
<mark> 是语义化标签,比 <span class="highlight"> 更合适,且默认有浅黄背景。但默认样式容易被父级 CSS 覆盖,必须强声明:
mark { background: #ffeb3b; color: #212121; padding: 0 2px; border-radius: 2px; }
另外注意:mark 是内联元素,如果它包裹的文本原本在 <p> 或 <div> 里,不影响块级流;但如果父容器设置了 user-select: none,高亮文字将无法被复制——这点常被忽略。
最麻烦的不是怎么标红,而是怎么在标红之后,还让页面保持可交互、可编辑、可选中。所有绕过文本节点的操作,本质上都是在透支 DOM 的稳定性。