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

Vue应用中实现DOM搜索词高亮及滚动至首个结果的方法

Vue 搜索词汇高亮实现方案

核心思路

要实现高亮不能直接替换元素的textContent(会破坏原有DOM结构),需递归遍历文本节点,将匹配词汇用带样式的<span>包裹;同时每次搜索前要清除之前的高亮,避免重复嵌套。

修改后的完整代码

// 清除已有高亮的方法
clearHighlights() {
  const highlights = document.querySelectorAll('.search-highlight');
  highlights.forEach(highlight => {
    const parent = highlight.parentNode;
    parent.replaceChild(document.createTextNode(highlight.textContent), highlight);
    parent.normalize(); // 合并相邻文本节点
  });
}

search() {
  // 先清除历史高亮
  this.clearHighlights();
  
  const searchTerm = this.searchTerm; // 假设searchTerm是Vue data中定义的搜索关键词
  if (!searchTerm.trim()) return; // 空关键词直接终止

  // 修正选择器:body后加空格,选中body下所有符合条件的子元素
  const elements = document.querySelectorAll('body *:not(script):not(style):not(title):not(.search-highlight)');
  
  let firstMatch = null;

  // 递归处理文本节点的函数
  const highlightText = (element) => {
    // 跳过已高亮节点,避免重复处理
    if (element.classList?.contains('search-highlight')) return;

    for (let i = 0; i < element.childNodes.length; i++) {
      const node = element.childNodes[i];
      // 仅处理文本节点
      if (node.nodeType === Node.TEXT_NODE) {
        const text = node.textContent;
        const regex = new RegExp(`(${searchTerm})`, 'gi'); // g全局匹配,i不区分大小写
        if (regex.test(text)) {
          // 将文本分割为匹配/非匹配片段
          const fragments = text.split(regex);
          const fragment = document.createDocumentFragment();
          
          fragments.forEach((part, index) => {
            if (index % 2 === 1) { // 奇数位为匹配的关键词
              const span = document.createElement('span');
              span.className = 'search-highlight';
              span.textContent = part;
              // 记录第一个匹配项用于滚动
              if (!firstMatch) firstMatch = span;
              fragment.appendChild(span);
            } else {
              fragment.appendChild(document.createTextNode(part));
            }
          });
          
          // 替换原文本节点
          element.replaceChild(fragment, node);
        }
      } else {
        // 非文本节点,递归处理子节点
        highlightText(node);
      }
    }
  };

  // 遍历所有目标元素执行高亮
  elements.forEach(element => highlightText(element));

  // 滚动到第一个匹配项
  if (firstMatch) {
    firstMatch.scrollIntoView({ behavior: 'smooth', block: 'center' });
  }
}

高亮样式(添加到Vue的<style>中)

.search-highlight {
  background-color: #ffeb3b;
  padding: 2px 4px;
  border-radius: 2px;
  font-weight: bold;
}

注意事项

  • searchTerm需在Vue的data中定义,示例:data() { return { searchTerm: '' } }
  • 递归处理时跳过已高亮节点,避免<span>嵌套重复
  • 使用document.createDocumentFragment减少DOM操作次数,提升性能
  • 正则修饰符gi可按需调整,比如去掉i则区分大小写

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 06:35:11