跨 HTML 标签文本高亮

67 阅读1分钟

<!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>    

高亮相同标签内文本:

image.png

高亮跨标签文本:

image.png

image.png