You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

不使用document.body.innerHTML如何实现网页指定词汇高亮

无DOM破坏的页面词汇高亮实现方案

你当前使用的document.body.innerHTML全局替换方案会重建整个页面DOM树,原本绑定的事件监听、表单输入状态、运行时持有的DOM引用都会全部失效,确实不适合生产环境使用。

可行方案的核心逻辑是仅遍历操作文本节点,不改动原有元素节点的结构与属性,完全不会影响页面原有交互,具体实现如下:

实现思路

  • 递归遍历DOM树,跳过script/style/noscript/textarea/input这类不需要处理内容的标签
  • 只对类型为文本(nodeType=3)的节点做关键词匹配
  • 将匹配到关键词的文本节点拆分为「普通文本片段+高亮span节点」的组合,用文档碎片拼接后替换原文本节点
  • 全程不修改其他已有元素的属性、结构,不会触发原有DOM的销毁重建

可直接使用的实现代码

function highlightKeyword(keyword, bgColor = 'YELLOW') {
  const skipTagSet = new Set(['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT']);
  // 转义关键词里的正则特殊字符,避免匹配异常
  const escapeReg = /[.*+?^${}()|[\]\\]/g;
  const matchReg = new RegExp(keyword.replace(escapeReg, '\\$&'), 'g');

  function traverse(node) {
    // 处理元素节点:跳过黑名单标签,递归遍历子节点
    if (node.nodeType === Node.ELEMENT_NODE) {
      if (skipTagSet.has(node.tagName)) return;
      // 倒序遍历子节点,避免节点替换导致的索引偏移问题
      for (let i = node.childNodes.length - 1; i >= 0; i--) {
        traverse(node.childNodes[i]);
      }
      return;
    }
    // 处理文本节点:匹配关键词并拆分节点
    if (node.nodeType === Node.TEXT_NODE) {
      const originText = node.textContent;
      matchReg.lastIndex = 0;
      if (!matchReg.test(originText)) return;
      matchReg.lastIndex = 0;

      const nodeFragment = document.createDocumentFragment();
      let lastPos = 0;
      let matchRes;
      while ((matchRes = matchReg.exec(originText)) !== null) {
        // 插入匹配位置前的普通文本
        if (matchRes.index > lastPos) {
          nodeFragment.appendChild(
            document.createTextNode(originText.slice(lastPos, matchRes.index))
          );
        }
        // 插入高亮节点
        const highlightNode = document.createElement('span');
        highlightNode.style.backgroundColor = bgColor;
        highlightNode.textContent = matchRes[0];
        nodeFragment.appendChild(highlightNode);
        lastPos = matchReg.lastIndex;
      }
      // 插入末尾剩余的普通文本
      if (lastPos < originText.length) {
        nodeFragment.appendChild(
          document.createTextNode(originText.slice(lastPos))
        );
      }
      // 替换原文本节点
      node.parentNode.replaceChild(nodeFragment, node);
    }
  }

  traverse(document.body);
}

// 调用示例:高亮页面中所有的TEST关键词
highlightKeyword('TEST');

方案优势

  • 不会破坏任何原有DOM的交互逻辑、事件绑定、表单状态
  • 自动过滤不需要处理的特殊标签,不会误改脚本、样式、输入框内的内容
  • 使用DocumentFragment做节点批量更新,渲染性能更高

针对异步动态加载的内容,只需要在内容渲染完成后,对新增的DOM容器调用该方法即可完成增量高亮,不需要重复处理已经处理过的节点。

内容的提问来源于stack exchange,提问作者Vicky Lahkar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.03 08:03:22