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 忽略大小写。
立即学习“Java免费学习笔记(深入)”;
避免重复高亮与清除旧标记
多次搜索时,若不清理之前加的 ,会导致嵌套标签或样式错乱。建议每次执行前先移除已有高亮:
- 用
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');











