利用原生JS实现类似浏览器查找高亮功能

在完成 Navify 时,增加一个类似浏览器ctrl+f查找并该高亮的功能,在此进行一点总结:

需求

.content中有许多.box,需要在.box中找出搜索的字符串,再将无搜索结果的.box隐藏掉,此外还要将字符串高亮。这个页面用vue.js实现了数据交互,不想用jquery来实现得查找高亮功能,得用原生js来实现该功能。

原理

将各个.box的文本内容提取,利用正则判断是否匹配字符串,若无搜索字符串,则隐藏该.box;否则继续找到具体的与该字符串匹配的结点及文本。通过对父节点的childNodes,然后利用nodeType筛选出文本结点,并利用匹配字符串将该文本结点分割,然后给匹配字符串加上<span class="search-highlight">,同时将原文本结点放入<template>中暂存,最后一起拼接后插入替换匹配结点。
更改或删除搜索的字符串时,将去掉.search-highlight,遍历所有的.search-highlight,找到里面父节点中的<template>,将<template>内容与父节点的内容替换,从而达到复原的效果。

思路&代码

// 原生事件监听
document.querySelector("search").addEventListener('input', function(e){
    var target = e.target,
        value = target.value;  // value即搜索的字符串
    const text = String(value).trim();
    const reg = new RegExp(text, 'ig'); // 匹配全局大小写
    const content = document.querySelector('.content');
    const box = document.querySelectorAll('.box');
    this.rmHighlight(content); // 移除所有之前的高亮内容
    box.forEach((el) => { // 遍历.box
        el.classList.remove('hidden'); // 清除之前无搜索结果时隐藏的.box
        if (!text) return; // 如果搜索的字符串为空,不进行下列操作
        let match = false; // 该box内是否含有匹配内容
        const range = el.querySelectorAll('.section-heading, .list-title, .item-name'); // 可搜索区域
        range.forEach((item) => {
            if (item.innerText.match(reg)) {
                this.highlight(item, text); // 目标结点匹配则执行高亮标记函数
                match = true;
            }
        });
        if (!match) { // 是否有匹配,从而对.box进行隐藏
            el.classList.add('hidden');
        } else {
            el.classList.remove('hidden');
        }
    });
}
// highlight函数
function highlight(el, value){
    const childList = el.childNodes;
    if (!childList.length || !value.length) return; // 无子节点或无查询值,则不进行下列操作
    const reg = new RegExp(value, 'ig');
    childList.forEach((el) => { // 遍历其内子节点
        if (el.nodeType === 1 // 如果是元素节点
            && el.classList && !el.classList.contains('search-highlight') // 而且没有被标记高亮
            && !/(script|style|template)/i.test(el.tagName)) { // 并且元素标签不是script或style或template等特殊元素
            this.highlight(el, value); // 那么就继续遍历(递归)该元素节点
        } else if (el.nodeType === 3) { // 如果是文本节点
            const highlightList = el.data.match(reg); // 得出文本节点匹配到的字符串数组
            if (!highlightList) return;
            const splitTextList = el.data.split(reg); // 分割多次匹配
            // 遍历分割的匹配数组,将匹配出的字符串加上.highlight并依次插入DOM
            el.parentNode.innerHTML = splitTextList.reduce(
                (html, splitText, i) =>
                    html + splitText + (
                        (i < splitTextList.length - 1)
                        ? `<span class="search-highlight">${highlightList[i]}</span>`
                        : `<template search-highlight>${el.data}</template>`
                    ), // 同时给为匹配的template用于后续恢复
                '');
        }
    });
}
// 移除.highlight函数
function rmHighlight(el) {
    const highlightSpans = el.querySelectorAll('span.search-highlight');
    highlightSpans.forEach((el) => { // 找到所有.highlight并遍历
        if (!el.parentNode) return;
        const template = el.parentNode.querySelector('template[search-highlight]');
        if (!template) return;
        // 找到父节点中的template,将自己内容替换为template内容
        el.parentNode.innerHTML = el.parentNode.querySelector('template[search-highlight]').innerHTML;
    });
}

完整代码参见 navify (Github)

利用原生JS实现类似浏览器查找高亮功能(转载)的更多相关文章

  1. <<< 网页中如何利用原生js和jquery储存cookie

    javascript当中的cookie机制,使应用达到了真正的全局变量的要求,cookie是浏览器提供的一种机制,它将document 对象的cookie属性提供给JavaScript.可以由Java ...

  2. 利用原生js制做数据管理平台,适合初学者学习

    摘要:数据管理平台在当今社会中运用十分广泛,我们在应用过程中,要对数据进行存储,管理,以及删除查询等操作,而我们在实际设计的时候,大牛们大多用到的是JQuery,而小白对jq理解也较困难,为了让大家回 ...

  3. 利用原生js做数据管理平台

    摘要:数据管理平台在当今社会中运用十分广泛,我们在应用过程中,要对数据进行存储,管理,以及删除查询等操作,而我们在实际设计的时候,大牛们大多用到的是JQuery,而小白对jq理解也较困难,为了让大家回 ...

  4. 利用原生JS实现网页1920banner图滚动效果

    内容描述:随着PC设备硬件性能的进步和分辨率的不断提高,现在主流网站逐渐开始采用1920banner图,为适应这一趋势,博主设计了1920banner图的滚动效果,代码利用了原生JS实现了1920ba ...

  5. 原生js实现 常见的jquery的功能

    原生选择器   充分利用 bind(this)绑定 <div id="box"> <ul> <li >111 </li> <l ...

  6. jquery与原生JS实现增加、减小字号功能

    预览效果: 实现代码: <!DOCTYPE html> <html lang="en"> <head> <meta charset=&qu ...

  7. 利用原生JS判断组合键

    <script type="text/javascript"> var isAlt = 0; var isEnt = 0; document.onkeydown = f ...

  8. 原生js解决跨浏览器兼容问题

    //跨浏览器兼容问题 Util = { //添加类名 add : function(ele,type,hand){ if(ele.addEventListener){ ele.addEventList ...

  9. 利用原生js的Dom操作实现简单的ToDoList的效果

    效果如下: 前端及js代码如下: <!DOCTYPE html> <html lang="en"> <head> <meta charse ...

随机推荐

  1. 消息中间件 | 消息协议 | MQTT3.1.1 -- 《分布式 消息中间件实践》笔记

    1999年,IBM和合作伙伴共同发明MQTT协议 14年,MQTT正式成为推荐的物联网传输协议标准 常应用于很多机器计算能力有限.底带宽.网络不可靠的远程通信应用场景中.   主要概念     MQT ...

  2. Python网络爬虫(四)

    关于Robots协议 Robots协议也称为爬虫协议,是网络爬虫排除标准(Robots Exclusion Protocol),用来告诉爬虫和搜索引擎哪些页面可以抓取,哪些不可以抓取.因为我们如果无限 ...

  3. springBoot实现socketio

    https://github.com/mrniko/netty-socketio-demo https://github.com/mrniko/netty-socketio

  4. Processes and Application Life Cycle

    进程的生命期 Android系统会尽量维持一个进程的生命,直到最终需要为新的更重要的进程腾出内存空间.为了决定哪个该杀哪个该留,系统会跟据运行于进程内的组件的和组件的状态把进程置于不同的重要性等级.当 ...

  5. 记录一个在线压缩和还原压缩js代码的工具

    packer – javascript 压缩工具 http://dean.edwards.name/packer/ Javascript Beautifier ---可以恢复某些压缩工具压缩的js代码 ...

  6. c/c++ socket发送http请求访问网站

    这几天课比较少,校园网上网要认证才能上网,每次必须输入学号密码,为了方便,写了一个自动登录以及如果在线,登录自服务系统强制下线的小工具. 强制下线思路:获取sessionID----------> ...

  7. [luogu 1660]数位平方和

    题目描述 定义S(n)表示n的各个数位的k次方的和.定义$H(n)=min{n,S(n),H(S(n))}$. 求$$\sum _{i=A} ^{B} {H(i)} \mod 10000007$$ 输 ...

  8. Hibernate基础案例1

    使用到的是MySQL数据库 1.在项目中先引入jar包,并添加引用 <dependencies> <dependency> <groupId>junit</g ...

  9. hibernate课程 初探单表映射1-1 第一章

    本章内容: 1 什么是orm 2 hibernate简介 3 编写第一个hibernate小例子

  10. ngnix入门配置

    文件1.首先到ngnix下载页面下载你操作系统对应的ngnix压缩包    http://nginx.org/en/download.html 博主我是window10操作系统  上面是我解压之后放的 ...