实现页内文字搜索并高亮

287 阅读1分钟

思路


1、先获取到搜索区域的dom和其html;

2、在html中通过正则匹配搜索的内容;

3、通过replace把匹配到的内容更换为带标签的高亮样式,比如<span style="color:red">key</span>;

4、通过scrollIntoView函数滚动到第一个高亮元素。

其他:本文通过vue3的hook方式实现。

实现代码

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

export default ({ id }) => {

    const search_key = ref('');// 搜索关键字
    let contentDom = null;// 搜索区域dom
    let contentOriginalHtml = '';// 全文初始html
    const noReg = /\d|[a-zA-Z]|\<|\>|\/|\-/; // 不需要匹配的字符

    // 监听搜索关键字变化-此处可添加防抖,或者导出为方法在外部调用
    watch(() => search_key.value, (newVal) => {
        reset();// 恢复原始html
        newVal && search(newVal);// 搜索并高亮
    })

    // 获取dom和原始html
    const getBase = () => {
        nextTick(() => {
            contentDom = document.getElementById(id);
            contentOriginalHtml = contentDom.innerHTML;
        })
    }

    // 恢复
    const reset = () => {
        contentDom.innerHTML = contentOriginalHtml;
    }

    // 搜索并高亮
    const search = (keyword) => {
        if (noReg.test(keyword)) {
            return;
        }
        const searchRegExp = new RegExp(keyword, 'ig');
        contentDom.innerHTML = contentOriginalHtml.replace(searchRegExp, (matched) => {
            return `<span style="color:#F56C6C" class="search_span">${matched}</span>`
        })
        scrollToFirst('search_span');
    }

    // 滚动到第一个
    const scrollToFirst = (className) => {
        const doms = document.getElementsByClassName(className);// 获取高亮元素列表
        if (!doms || doms.length === 0) return;
        doms[0].scrollIntoView({ behavior: "smooth" });
    }

    onMounted(() => {
        getBase();// 获取dom和原始html;getBase也可以导出到外部进行调用
    })

    return { search_key }
}

使用

<template>
    <!-- 输入搜索关键字 -->
    <input v-model="search_key" />
    <!-- 搜索区域div -->
    <div id="content">xxxxxxxxxxxx</div>
</template>

<script setup>
import usePageSearch from './usePageSearch';

// 页内搜索
const { search_key } = usePageSearch({ id: 'content' });// 传入搜索区域id

</script>