hightLight.js

import { ref, watch, nextTick } from 'vue';


// 共享关键词状态
const currentKeyword = ref('');

export const setGlobalHighlightKeyword = (keyword) => {
    currentKeyword.value = (keyword || '').trim();
};

// 清除高亮
export const clearGlobalHighlight = (container = document.body) => {
    const highlighted = container.querySelectorAll('span[style*="background: #555"]');
    highlighted.forEach(span => {
        if (span.parentNode) {
            const textNode = document.createTextNode(span.textContent);
            span.replaceWith(textNode);
        }
    });
};

const highlightNode = (node, keyword) => {
    if (!keyword || !node?.textContent) return;

    const parent = node.parentNode;
    if (!parent || !parent.isConnected) return;

    const text = node.textContent;
    const escapedKeyword = keyword.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
    const regex = new RegExp(`(${escapedKeyword})`, 'gi');
    if (!regex.test(text)) return;

    const temp = document.createElement('div');
    text.split(regex).forEach(part => {
        if (part.toLowerCase() === keyword.toLowerCase()) {
            const span = document.createElement('span');
            span.style.cssText = 'color:#ffff00;background: #555;font-weight: bold; font-size: 13px;';
            span.textContent = part;
            temp.appendChild(span);
        } else {
            temp.appendChild(document.createTextNode(part));
        }
    });

    if (!node.parentNode) return;

    const nextSibling = node.nextSibling;
    node.replaceWith(temp);

    if (nextSibling) {
        while (temp.lastChild) {
            parent.insertBefore(temp.lastChild, nextSibling);
        }
    } else {
        while (temp.firstChild) {
            parent.appendChild(temp.firstChild);
        }
    }
};

const walkAndHighlight = (element, keyword) => {
    if (!element.isConnected && element !== document.body) return;

    const walker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT, null);
    const nodes = [];
    let node;
    while (node = walker.nextNode()) {
        const parent = node.parentNode;
        if (
            parent &&
            ['INPUT', 'TEXTAREA', 'SCRIPT', 'STYLE'].includes(parent.tagName) ||
            parent.isContentEditable
        ) continue;
        nodes.push(node);
    }

    // 逆序处理,避免 DOM 变化影响遍历
    nodes.reverse().forEach(n => highlightNode(n, keyword));
};


export const GlobalHighlight = {

    mounted(el) {
        if (currentKeyword.value) {
            clearGlobalHighlight(el);
            walkAndHighlight(el, currentKeyword.value);
        }

        // 监听关键词变化
        watch(currentKeyword, (newVal) => {
            nextTick(() => {
                if (el.isConnected) {
                    clearGlobalHighlight(el);
                    if (newVal) {
                        walkAndHighlight(el, newVal);
                    }
                }
            });
        });
    },

    updated(el) {
        nextTick(() => {
            if (el.isConnected) {
                clearGlobalHighlight(el);
                if (currentKeyword.value) {
                    walkAndHighlight(el, currentKeyword.value);
                }
            }
        });
    },

    unmounted(el) {
        clearGlobalHighlight(el);
    }
};

export default GlobalHighlight;

应用:main.js 中

import GlobalHighlight, { setGlobalHighlightKeyword } from "~/composables/globalHighlight"

vue文件中:

import { setGlobalHighlightKeyword,clearGlobalHighlight} from '~/composables/globalHighlight';


// 点击搜索按钮
const handleSearch = async () => {

    await nextTick();
  if (queryParams.ORDER_NO) { setGlobalHighlightKeyword(queryParams.ORDER_NO) }
  if (queryParams.IVC_NO) { setGlobalHighlightKeyword(queryParams.IVC_NO) }
};


// 重置查询条件
const handleReset = () => {
    clearGlobalHighlight();
}

效果: 

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐