
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
</head>
<body>
<div id="jsContent">
<span>hhhhh前端开发发发发发前端开发+</span>
highlight test 前端前端开发
<span>发前发</span>
</div>
<script>
// 1、分析A节点的内容,高亮给定的的关键词,高亮方式为用<em>标签包裹
// 2、同一字符串中,优先匹配最长的关键词,且同一字符串只需高亮一次
// 例如:关键词test,字符串“tttesttest”中应高亮第一个“test”
// 3、不能跨标签高亮
// 4、关键词可能包含特殊字符,如“+”、“*”等
function highlight(word) {
if (!word) return;
const container = document.getElementById("jsContent");
if (!container) return;
// 高亮实现
function processNode(node, keywords) {
// 如果是文本节点
if (node.nodeType === Node.TEXT_NODE) {
let text = node.textContent;
let lastIndex = 0;
let fragments = [];
let matched = false;
// 逐一匹配关键词
for (let i = 0; i < keywords.length; i++) {
const keyword = keywords[i];
//构造相应的正则表达式,注意转义特殊字符
const regex = new RegExp(
keyword.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"),
"g"
);
let match;
if ((match = regex.exec(text))) {
matched = true;
// 添加匹配前的文本
if (match.index > lastIndex) {
fragments.push(text.substring(lastIndex, match.index));
}
// 添加高亮文本
const em = document.createElement("em");
em.textContent = match[0];
fragments.push(em);
lastIndex = match.index + match[0].length;
// 添加剩余文本
if (lastIndex < text.length) {
fragments.push(text.substring(lastIndex));
}
}
if (matched) break;
}
// 如果有匹配,替换原节点
if (fragments.length > 0) {
// const parent = node.parentNode;
// fragments.forEach((fragment) => {
// parent.insertBefore(
// typeof fragment === "string"
// ? document.createTextNode(fragment)
// : fragment,
// node
// );
// });
// parent.removeChild(node);
// (以下方式更优
const fragment = document.createDocumentFragment();
for (let item of fragments) {
if (typeof item === "string") {
fragment.appendChild(document.createTextNode(item));
} else {
fragment.appendChild(item);
}
}
node.parentNode.replaceChild(fragment, node);
}
}
} else if (
node.nodeType === Node.ELEMENT_NODE &&
node.nodeName !== "EM"
) {
// 递归处理子节点(跳过em标签)
const children = Array.from(node.childNodes);
for (let child of children) {
processNode(child, [...keywords]); // 传递keywords的副本
}
}
}
// 生成所有需要匹配的关键词(从长到短排序)
const keywords = [];
for (let i = word.length; i > 0; i--) {
keywords.push(word.substring(0, i));
}
// 开始处理
processNode(container, keywords);
}
highlight("前端开发");
</script>
</body>
</html>