17370845950

如何在javascript中实现搜索功能_怎样进行关键字高亮?
JavaScript搜索高亮需先清除旧mark标签,再遍历文本节点用转义后的正则匹配并包裹mark标签,避免XSS和结构破坏。

在 JavaScript 中实现搜索功能并高亮关键字,核心是两步:一是匹配文本中包含搜索词的部分,二是用 HTML 标签(如 )包裹匹配内容,再安全地插入页面。

基础搜索与高亮逻辑

不能直接用 innerHTML = str.replace(...) 粗暴替换,否则可能破坏原有标签结构或引发 XSS。正确做法是遍历文本节点,只对纯文本内容做匹配和包装。

  • 使用 document.querySelectorAll 定位要搜索的容器(如 .content
  • NodeIterator 或递归遍历其后代,筛选出 Node.TEXT_NODE
  • 对每个文本节点,用正则匹配搜索词(注意转义特殊字符、支持大小写可选)
  • 匹配成功后,用 document.createElement('mark') 创建高亮标签,把匹配段落塞进去
  • node.parentNode.replaceChild(newNode, node) 替换原节点

处理关键词转义与正则安全

用户输入的搜索词可能含正则元字符(如 .*?),直接放进 RegExp 会报错或误匹配。需先转义:

function escapeRegExp(string) {
  return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}

之后构造正则:new RegExp(escapeRegExp(keyword), 'gi') —— g 全局,i 忽略大小写。

避免重复高亮与清除旧标记

多次搜索时,若不清理之前加的 ,会导致嵌套标签或样式错乱。建议每次执行前先移除已有高亮:

  • container.querySelectorAll('mark') 找到所有高亮元素
  • 遍历它们,用 el.parentNode.replaceChild(el.firstChild, el) 还原文本
  • 或者更稳妥:先提取纯文本,再整体重新高亮(适合内容不复杂场景)

简单可用的封装函数示例

以下是一个轻量实用版本,适用于单个容器、支持中文和英文关键词:

function highlightText(container, keyword) {
  if (!keyword.trim()) return;

  // 清除旧 mark
  container.querySelectorAll('mark').forEach(el => {
    el.parentNode.replaceChild(document.createTextNode(el.textContent), el);
  });

  const reg = new RegExp(escapeRegExp(keyword), 'gi');
  const walker = document.createTreeWalker(
    container,
    NodeFilter.SHOW_TEXT,
    { acceptNode: node => (node.textContent.trim() ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT) }
  );

  let node;
  while (node = walker.nextNode()) {
    const matches = node.textContent.match(reg);
    if (matches) {
      const span = document.createElement('mark');
      span.style.backgroundColor = '#ffeb3b';
      span.style.color = '#212121';

      const replaced = node.textContent.replace(reg, match => {
        span.textContent = match;
        return span.outerHTML;
      });

      const temp = document.createElement('div');
      temp.innerHTML = replaced;
      while (temp.firstChild) {
        node.parentNode.insertBefore(temp.firstChild, node);
      }
      node.parentNode.removeChild(node);
    }
  }
}

调用方式:highlightText(document.querySelector('.article'), 'JavaScript');