HTML高亮关键字的完美解决方案

HTML教程 2025-08-05

项目中需要在网页中实现关键字高亮,原以为用 innerHTML.replace 即可,但实际遇到了许多问题。本文总结几种方法及最终的最佳方案。

方式一:简单正则替换

基本思路:直接用正则将关键字包裹成标签

const regex = new RegExp(keyword, 'g');
element.innerHTML = element.innerHTML.replace(regex, '' + keyword + '');

问题:

  • 污染原始 DOM,影响后续逻辑

  • 容易破坏结构,如属性中含有关键字或特殊符号

方式二:正则优化尝试

尝试规避标签和属性内容:

var safeKeyword = keyword.replace(/[-/\^$*+?.()|[]{}]/g, '\$&');
var finder = new RegExp('>[^<]*?' + safeKeyword + '[^<]*?<', 'g');
element.innerHTML = element.innerHTML.replace(finder, function(m) {
  return m.replace(new RegExp(safeKeyword, 'g'), '' + keyword + '');
});

缺陷: 依旧无法处理标签属性中含有 <> 的情况。

方式三:使用占位符处理标签

let html = element.innerHTML;
html = html.replace(//g, '[divStart]');
html = html.replace(/
/g, '[divEnd]'); html = html.replace(keyword, '' + keyword + ''); html = html.replace(/[divStart]/g, '
'); html = html.replace(/[divEnd]/g, '
');

问题: 若 placeholder 与关键字冲突,替换会出错,仍不安全。

最终方案:基于 DOM 节点递归处理

通过递归遍历 DOM,查找文本节点并替换关键字,无需操作 innerHTML,避免破坏结构。

function highlight(node, keyword) {
  const reg = new RegExp(keyword.replace(/[-/\^$*+?.()|[]{}]/g, '\$&'));
  if (node.nodeType === 3) {
    const match = node.data.match(reg);
    if (match) {
      const highlightEl = document.createElement("b");
      highlightEl.textContent = match[0];
      highlightEl.dataset.highlight = "y";
      const wordNode = node.splitText(match.index);
      wordNode.splitText(match[0].length);
      wordNode.parentNode.replaceChild(highlightEl, wordNode);
    }
  } else if (node.nodeType === 1 && node.dataset.highlight !== "y") {
    for (let i = 0; i < node.childNodes.length; i++) {
      highlight(node.childNodes[i], keyword);
    }
  }
}

优点:

  • 安全:不破坏原始 DOM

  • 灵活:可处理嵌套元素

  • 可控:通过 dataset 标记已高亮内容

总结

基于 DOM 的高亮方式是目前最稳定、安全的方案。建议大家在实际项目中直接采用递归遍历 + 文本节点替换的方式。