利用原生JS实现类似浏览器查找高亮功能(转载)
利用原生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实现类似浏览器查找高亮功能(转载)的更多相关文章
- <<< 网页中如何利用原生js和jquery储存cookie
javascript当中的cookie机制,使应用达到了真正的全局变量的要求,cookie是浏览器提供的一种机制,它将document 对象的cookie属性提供给JavaScript.可以由Java ...
- 利用原生js制做数据管理平台,适合初学者学习
摘要:数据管理平台在当今社会中运用十分广泛,我们在应用过程中,要对数据进行存储,管理,以及删除查询等操作,而我们在实际设计的时候,大牛们大多用到的是JQuery,而小白对jq理解也较困难,为了让大家回 ...
- 利用原生js做数据管理平台
摘要:数据管理平台在当今社会中运用十分广泛,我们在应用过程中,要对数据进行存储,管理,以及删除查询等操作,而我们在实际设计的时候,大牛们大多用到的是JQuery,而小白对jq理解也较困难,为了让大家回 ...
- 利用原生JS实现网页1920banner图滚动效果
内容描述:随着PC设备硬件性能的进步和分辨率的不断提高,现在主流网站逐渐开始采用1920banner图,为适应这一趋势,博主设计了1920banner图的滚动效果,代码利用了原生JS实现了1920ba ...
- 原生js实现 常见的jquery的功能
原生选择器 充分利用 bind(this)绑定 <div id="box"> <ul> <li >111 </li> <l ...
- jquery与原生JS实现增加、减小字号功能
预览效果: 实现代码: <!DOCTYPE html> <html lang="en"> <head> <meta charset=&qu ...
- 利用原生JS判断组合键
<script type="text/javascript"> var isAlt = 0; var isEnt = 0; document.onkeydown = f ...
- 原生js解决跨浏览器兼容问题
//跨浏览器兼容问题 Util = { //添加类名 add : function(ele,type,hand){ if(ele.addEventListener){ ele.addEventList ...
- 利用原生js的Dom操作实现简单的ToDoList的效果
效果如下: 前端及js代码如下: <!DOCTYPE html> <html lang="en"> <head> <meta charse ...
随机推荐
- EIGRP-8-路由器的邻接关系
EIGRP路由器之间会建立并维护邻接关系.EIGRP在默认情况下会动态发现邻居路由器.也可以通过工程师手动配置(静态)发现邻居. 通过向目的组播组地址224.0.0.10或FF02: : A发送E ...
- 转 安装EBS前期检查工具 - RDA - Health Check / Validation Engine Guide
http://blog.itpub.net/35489/viewspace-1295028/ 参考文档 RDA - Health Check / Validation Engine Gu ...
- B. Filya and Homework
http://codeforces.com/contest/714/problem/B 给定一个序列,对于每一个元素,只能 + 或者 - 一个数val.这个数一旦选定,就不能改. 问能否变成全部数字都 ...
- 类成员函数的重载、覆盖和隐藏区别 (C++)(转)
类成员函数的重载.覆盖和隐藏区别 (C++) 这是本人第一次写博客,主要是想记录自己的学习过程.心得体会,一是可以方便以后回顾相关知识,二是可以与大家相互学习交流. 关于C++中类成员函数的重载. ...
- 初学makefile
makefile 需要用到 常用命令.shell.正则表达式.gcc,比较综合. 今天写了一个做一个记录,以后系统总结一下. 目录结构:russia---------include.src.mian. ...
- Navicat for mysql远程连接数据库详解(1130错误解决方法)
用Navicat for mysql连接数据库测试下连接 如果出现1130错误 错误代码是1130,ERROR 1130: Host xxx.xxx.xxx.xxx is not allowed to ...
- 与 HTML4 比较,HTML5 废弃了哪些元素?
frame frameset noframe applet big center basefront
- Android入门:Activity生命周期
一.Activity生命周期介绍 我们在学Java Web时会学到Servlet的生命周期,因此对生命周期的概念已经有一定了解,简单地说就是某个事物从出生到死亡的过程. Activity也存在声明周期 ...
- 在Ubuntu中安装MySQL
在Ubuntu中安装MySQL Ubuntu实用工具系列文章,将介绍基于Linux ubuntu的各种工具软件的配置和使用.有些工具大家早已耳熟能详,有些工具经常用到但确依然陌生.我将记录我在使用操作 ...
- Android 使用GreenDao 添加字段,删除表,新增表操作
GreenDao 给我个人感觉 比一般的ORM框架要好很多,虽然说上手和其他的比起来,较复杂,但是如果使用熟练以后,你会爱上这个框架的 用这些ORM 框架给我的感觉都是,当升级时,都需要进行数据库所有 ...