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.crea
teTextNode(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');