一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

index.html如何添加网页内的内容搜索高亮功能

时间:2026-06-28 10:00:46 编辑:袖梨 来源:一聚教程网

不能对 innerHTML 做正则替换,因为浏览器不自动转义 HTML 字符,关键词含 alert(1)、& 等会破坏标签结构,导致脚本执行、XSS 风险或 DOM 解析错误。

直接用 innerHTML 替换关键词高亮,90% 的情况下会出问题:表单值清空、事件监听器丢失、imgonerror 失效、甚至破坏嵌套结构。必须只操作文本节点。

为什么不能对 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 的稳定性。

热门栏目