js高亮文本

高亮文本

const inputs = [
  "这是一个普通文本,包含关键字测试。",
  '<p style="font-size: 10px">这是一个<span>GVM</span> <strong>测试</strong>内容。</p>',
];

const keywords = ["测试", "GVM"];
function highlightKeyword(inputContent, keyword) {
  if (!keyword) return inputContent; // 如果没有关键字,直接返回原始内容

  // 转义用户输入的关键字,避免正则表达式特殊字符冲突
  const escapeRegExp = (str) =>
    str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");

  // 创建匹配关键字的正则表达式
  const keywordRegex = new RegExp(`(${escapeRegExp(keyword)})`, "gi");

  // 判断是否为普通文本(没有 HTML 标签)
  const isPlainText = !/<[^>]+>/.test(inputContent);

  if (isPlainText) {
    // 普通文本处理
    return inputContent.replace(
      keywordRegex,
      '<span class="highlight">$1</span>'
    );
  }

  // HTML 内容处理
  const parser = new DOMParser();
  const doc = parser.parseFromString(inputContent, "text/html");

  // 遍历节点,处理文本高亮
  function traverseNodes(node) {
    if (node.nodeType === Node.TEXT_NODE) {
      // 替换关键字为高亮的内容
      const parent = node.parentNode;
      const highlightedHTML = node.textContent.replace(
        keywordRegex,
        '<span class="highlight">$1</span>'
      );

      // 用安全的 HTML 替换
      if (highlightedHTML !== node.textContent) {
        const temp = document.createElement("div");
        temp.innerHTML = highlightedHTML;
        while (temp.firstChild) {
          parent.insertBefore(temp.firstChild, node);
        }
        parent.removeChild(node);
      }
    } else if (node.nodeType === Node.ELEMENT_NODE) {
      // 递归处理子节点
      Array.from(node.childNodes).forEach(traverseNodes);
    }
  }

  traverseNodes(doc.body);

  // 返回处理后的 HTML
  return doc.body.innerHTML;
}

跨标签命中

function highlightKeyword(inputContent, keyword) {
  if (!keyword) return inputContent; // 如果没有关键字,直接返回原始内容

  // 转义用户输入的关键字,避免正则表达式特殊字符冲突
  const escapeRegExp = (str) =>
    str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");

  // 创建匹配关键字的正则表达式
  const keywordRegex = new RegExp(`(${escapeRegExp(keyword)})`, "gi");

  // 使用 DOMParser 解析 HTML
  const parser = new DOMParser();
  const doc = parser.parseFromString(inputContent, "text/html");

  // 提取纯文本和对应节点
  const textNodes = [];
  function extractTextNodes(node) {
    if (node.nodeType === Node.TEXT_NODE) {
      textNodes.push({ node, text: node.textContent });
    } else if (node.nodeType === Node.ELEMENT_NODE) {
      Array.from(node.childNodes).forEach(extractTextNodes);
    }
  }
  extractTextNodes(doc.body);

  // 合并纯文本
  const combinedText = textNodes.map((item) => item.text).join("");

  // 查找关键字在纯文本中的位置
  const matches = [];
  let match;
  while ((match = keywordRegex.exec(combinedText)) !== null) {
    matches.push({ start: match.index, end: match.index + match[0].length });
  }

  // 在原始文本节点中插入高亮
  let currentIndex = 0;
  matches.forEach(({ start, end }) => {
    textNodes.forEach(({ node, text }) => {
      const nodeEnd = currentIndex + text.length;

      if (start < nodeEnd && end > currentIndex) {
        const localStart = Math.max(start - currentIndex, 0);
        const localEnd = Math.min(end - currentIndex, text.length);

        const highlightedText =
          text.slice(0, localStart) +
          `<span class="highlight">${text.slice(localStart, localEnd)}</span>` +
          text.slice(localEnd);

        const temp = document.createElement("div");
        temp.innerHTML = highlightedText;

        // 替换节点
        const parent = node.parentNode;
        while (temp.firstChild) {
          parent.insertBefore(temp.firstChild, node);
        }
        parent.removeChild(node);

        // 更新当前文本
        node.textContent = text;
      }

      currentIndex += text.length;
    });
  });

  // 返回处理后的 HTML
  return doc.body.innerHTML;
}

关键字忽略大小写

function highlightKeyword(inputContent, keyword) {
  if (!keyword) return inputContent; // 关键字为空直接返回

  const escapeRegExp = (str) => str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");

  // 统一大小写匹配
  const keywordLower = keyword.toLowerCase();
  const regex = new RegExp(`(${escapeRegExp(keywordLower)})`, "gi"); // 🔥【提前正则表达式】

  // 判断是否是普通文本
  const isPlainText = !/<[a-z][\s\S]*>/i.test(inputContent);
  if (isPlainText) {
    return inputContent.replace(regex, `<span class="highlight">$1</span>`);
  }

  // 解析 HTML
  const parser = new DOMParser();
  const doc = parser.parseFromString(inputContent, "text/html");

  const textNodes = [];
  function extractTextNodes(node) {
    if (node.nodeType === Node.TEXT_NODE) {
      textNodes.push({ node, text: node.textContent });
    } else if (node.nodeType === Node.ELEMENT_NODE) {
      Array.from(node.childNodes).forEach(extractTextNodes);
    }
  }
  extractTextNodes(doc.body);

  // 合并所有文本(保持原顺序)
  let combinedText = textNodes.map((item) => item.text).join("");

  // 在合并后的文本中查找匹配位置(忽略大小写)
  const matches = [];
  let match;
  while ((match = regex.exec(combinedText)) !== null) {
    matches.push({ start: match.index, end: match.index + match[0].length });
  }

  // 在原始 HTML 结构中插入高亮标签
  let currentIndex = 0;
  matches.forEach(({ start, end }) => {
    textNodes.forEach(({ node, text }) => {
      const textLower = text.toLowerCase();
      const nodeEnd = currentIndex + text.length;

      if (start < nodeEnd && end > currentIndex) {
        const localStart = Math.max(start - currentIndex, 0);
        const localEnd = Math.min(end - currentIndex, text.length);

        // 保留原始大小写的文本进行替换
        const highlightedText =
          text.slice(0, localStart) +
          `<span class="highlight">${text.slice(localStart, localEnd)}</span>` +
          text.slice(localEnd);

        const temp = document.createElement("div");
        temp.innerHTML = highlightedText;

        const parent = node.parentNode;
        while (temp.firstChild) {
          parent.insertBefore(temp.firstChild, node);
        }
        parent.removeChild(node);
      }

      currentIndex += text.length;
    });
  });

  return doc.body.innerHTML;
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值