<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>跨 HTML 标签文本高亮</title>
<style>
.highlight {
background-color: yellow;
}
</style>
</head>
<body>
<div id="content">
<p>在当今这个 <strong>信息爆炸</strong> 的时代,</p>
<p>人们每天都会接触到 <em>大量</em> 的数据和信息。</p>
<p>其中,<span>有效信息</span> 的筛选和利用变得尤为重要。</p>
<p>如何从 <b>繁杂</b> 的信息中提取出对自己有用的部分,</p>
<p>已经成为了 <i>每个人</i> 都需要面对的问题。</p>
</div>
<input type="text" id="searchInput" placeholder="输入要高亮的文本">
<button onclick="highlightText()">高亮</button>
<button onclick="removeHighlight()">移除高亮</button>
<script>
function highlightText() {
const searchInput = document.getElementById('searchInput');
const searchTerm = searchInput.value;
if (searchTerm === '') return;
console.log('searchTerm field:', searchTerm)
const content = document.getElementById('content');
const walker = document.createTreeWalker(content, NodeFilter.SHOW_TEXT, null, false);
const allTextNodes = [];
while (walker.nextNode()) {
allTextNodes.push(walker.currentNode);
}
console.log(' allTextNodes.map(node => node.textContent) field:', allTextNodes.map(node => node.textContent))
const combinedText = allTextNodes.map(node => node.textContent).join('');
let index = combinedText.indexOf(searchTerm);
console.log('combinedText field:', combinedText)
console.log('index field:', index)
if (index === -1) return;
let charCount = 0;
let searchIndex = 0; // 用于记录搜索词当前匹配到的位置
for (let i = 0; i < allTextNodes.length; i++) {
const node = allTextNodes[i];
const nodeText = node.textContent;
const nodeLength = nodeText.length;
console.log('nodeText field:', nodeText)
if (charCount + nodeLength > index && searchIndex < searchTerm.length) {
let start = 0;
// 确定搜索词在当前节点的起始位置
while (charCount < index) {
charCount++;
start++;
}
let end = start;
// 确定搜索词在当前节点的结束位置
while (searchIndex < searchTerm.length && end < nodeLength) {
console.log('nodeText field:', nodeText, end)
if (searchTerm[searchIndex] === nodeText[end]) {
searchIndex++;
end++;
} else if (/\s/.test(searchTerm[searchIndex]) && /\s/.test(nodeText[end])) {
searchIndex++;
end++;
} else {
break; // 匹配失败,跳出循环
}
}
// 创建搜索词之前的文本节点
const before = document.createTextNode(nodeText.slice(0, start));
// 创建用于高亮显示的 span 元素
const highlight = document.createElement('span');
highlight.classList.add('highlight');
// 设置高亮文本内容
highlight.textContent = nodeText.slice(start, end);
// 创建搜索词之后的文本节点
const after = document.createTextNode(nodeText.slice(end));
const parent = node.parentNode;
// 若存在搜索词之前的文本,插入到原节点前
if (before.textContent) {
parent.insertBefore(before, node);
}
// 插入高亮元素到原节点前
parent.insertBefore(highlight, node);
// 若存在搜索词之后的文本,插入到原节点前
if (after.textContent) {
parent.insertBefore(after, node);
}
// 移除原节点
parent.removeChild(node);
if (searchIndex === searchTerm.length) {
break; // 搜索词全部匹配完成,跳出循环
}
}
charCount += nodeLength;
}
}
function removeHighlight() {
const highlights = document.querySelectorAll('.highlight');
highlights.forEach(highlight => {
const parent = highlight.parentNode;
const text = document.createTextNode(highlight.textContent);
parent.insertBefore(text, highlight);
parent.removeChild(highlight);
});
}
</script>
</body>
</html>
高亮相同标签内文本:
高亮跨标签文本: