实现一个简单的 ctrl+ f 搜索

news/2024/4/29 19:49:56/文章来源:https://blog.csdn.net/weixin_41897680/article/details/126672714

前言

浏览器可以通过ctrl + f 来实现,这个功能真的很不错,但是如何实现类似的功能呢?想了很久,感觉可以基于文本选中来实现

复制时的效果是这样的
在这里插入图片描述
搜索时的效果
在这里插入图片描述
是不是除了颜色不一样,其他都一样呢

文本选中样式设置

其实文本选中的样式是可以被自定义的,可以通过CSS3的伪类选择器::selection来设置文本被选中时的状态。比如:

::selection {background: #ff9632;
}

在这里插入图片描述
这样是不是就根搜索时的样式一样了

通过js来实现文本选中

参考:

https://developer.mozilla.org/zh-CN/docs/Web/API/Range

javascript里文字选中/选中文字

获取、清除选中的文字

获取

//获取选中的文字
document.getElementById("get").onclick = function () {var txt = window.getSelection ? window.getSelection() : document.selection.createRange().text;alert(txt);//alert默认调用了toString()
}

在这里插入图片描述

清除

 //清除选中的文字document.getElementById("set").onclick = function () {window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();}

实现选中

全部选中

const selectAll = () => {// 创建range对象const range = document.createRange();// 获取要选中的文本const node = document.getElementsByClassName('container')[0];range.selectNodeContents(node);const selection = window.getSelection();selection?.removeAllRanges();selection?.addRange(range);
};
  • Range.selectNodeContents() 方法用于设置 Range,使其包含一个 Node 的内容。
  • Window.getSelection 返回一个 Selection 对象,表示用户选择的文本范围或光标的当前位置。
  • Selection.removeAllRanges() 方法会从当前 selection 对象中移除所有的 range 对象,取消所有的选择只 留下anchorNodefocusNode属性并将其设置为 null
  • addRange:向选区添加一个区域

在这里插入图片描述

设置开始截止位置选中

<template><el-button type="primary" @click="selectAll">全部选中</el-button><div class="container"><p>这是一段默认有开始截止位置的文本</p></div>
</template><script setup lang="ts">
const selectAll = () => {// 创建range对象const range = document.createRange();// 获取开始节点const startNode = document.getElementsByTagName('p').item(0)?.firstChild;if (startNode) {range.setStart(startNode, 2);range.setEnd(startNode, 5);const selection = window.getSelection();selection?.removeAllRanges();selection?.addRange(range);}
};</script>

如果起始节点类型是 TextComment, or CDATASection之一, 那么startOffset指的是从起始节点算起字符的偏移量。

在这里插入图片描述
跨段选中

<template><el-button type="primary" @click="selectAll">跨行选中</el-button><div class="container"><span>太阳当空照,<br></span><span>花儿对我笑。<br></span><span>小鸟说:“早,早,早,<br></span><span>你为什么背上小书包?”<br></span><span>我去上学校,<br></span><span>天天不迟到。<br></span><span>爱学习,爱劳动,<br></span><span>长大要为祖国立功劳。<br></span></div>
</template><script setup lang="ts">
const selectAll = () => {// 创建range对象const range = document.createRange();// 获取开始节点const startNode = document.getElementsByClassName('container')[0];// childNode会将html换行加进去for (var i = 0; i < startNode.childNodes.length; i++) {console.log(`节点:${i + 1}`, startNode.childNodes[i], startNode.childNodes[i].nodeName);if (startNode.childNodes[i].nodeName == '#text' && !/\s/.test(startNode.childNodes.nodeValue)) {startNode.removeChild(startNode.childNodes[i]);}}var startOffset = 1;range.setStart(startNode, startOffset);var endOffset = startNode.childNodes.length - 2;range.setEnd(startNode, endOffset);const selection = window.getSelection();selection?.removeAllRanges();selection?.addRange(range);
};</script>

在这里插入图片描述

跨段文字特定位置选中

<template><el-button type="primary" @click="selectAll">跨行选中</el-button><div class="container"><span>太阳当空照,<br></span><span>花儿对我笑。<br></span><span>小鸟说:“早,早,早,<br></span><span>你为什么背上小书包?”<br></span><span>我去上学校,<br></span><span>天天不迟到。<br></span><span>爱学习,爱劳动,<br></span><span>长大要为祖国立功劳。<br></span></div>
</template><script setup lang="ts">
const selectAll = () => {// 创建range对象const range = document.createRange();// 获取开始节点const startNode = document.getElementsByClassName('container')[0];// childNode会将html换行加进去for (var i = 0; i < startNode.childNodes.length; i++) {console.log(`节点:${i + 1}`, startNode.childNodes[i], startNode.childNodes[i].nodeName);if (startNode.childNodes[i].nodeName == '#text' && !/\s/.test(startNode.childNodes.nodeValue)) {startNode.removeChild(startNode.childNodes[i]);}}range.setStart(startNode.childNodes[5].firstChild, 2);range.setEnd(startNode.childNodes[7].firstChild, 8);const selection = window.getSelection();selection?.removeAllRanges();selection?.addRange(range);
};</script>

在这里插入图片描述

ctrl + f 简单demo

<template><div><el-input v-model="inputValue" placeholder="请输入" /><el-button type="primary" @click="search">搜索</el-button><el-button type="primary" @click="previous">上一个</el-button><el-button type="primary" @click="next">下一个</el-button><div class="container" id="container"><p> 床前明月光,疑是地上霜。</p><p>举头望明月,低头思故乡。</p></div></div>
</template><script setup lang="ts">
import { ElMessage } from 'element-plus';
import { ref } from 'vue';const inputValue = ref('');const findNode = ref();const index = ref(-1);const search = () => {// 获取容器const container = document.getElementById('container');// 获取所有文本const allText = container?.innerText;if (allText && allText.includes(inputValue.value)) {// 获取所有节点const containerAllNode = container.childNodes;console.log(containerAllNode);// 用于保存找到的节点findNode.value = [];for (let i = 0; i < containerAllNode.length; i++) {// 遍历查询节点if (containerAllNode[i].textContent?.includes(inputValue.value)) {findNode.value.push(containerAllNode[i]);}}// 默认选中第一个if (findNode.value && findNode.value.length > 0) {index.value = 0;setSelect(0);}} else {ElMessage.warning('未匹配到');}
};const previous = () => {if (index.value > 0) {index.value -= 1;} else {index.value = findNode.value.length - 1;}setSelect(index.value);
};const next = () => {if (index.value < findNode.value.length - 1) {index.value += 1;} else {index.value = 0;}setSelect(index.value);
};const setSelect = (index) => {const range = document.createRange();range.selectNodeContents(findNode.value[index]);const selection = window.getSelection();selection?.removeAllRanges();selection?.addRange(range);
};</script>
<style lang="scss" scoped>
.container {width: 400px;height: 200px;margin-left: 100px;border: 1px solid red;::selection {background: #ff9632;}
}
</style>

在这里插入图片描述
改进版

<template><div><el-input v-model="inputValue" placeholder="请输入" /><el-button type="primary" @click="search">搜索</el-button><el-button type="primary" @click="previous">上一个</el-button><el-button type="primary" @click="next">下一个</el-button><div class="container" id="container"><p> 床前明月光,疑是地上霜。</p><p>举头望明月,低头思故乡。</p></div></div>
</template><script setup lang="ts">
import { ElMessage } from 'element-plus';
import { ref } from 'vue';const inputValue = ref('');const findNode = ref();const index = ref(-1);const search = () => {// 获取容器const container = document.getElementById('container');// 获取所有文本const allText = container?.innerText;if (allText && allText.includes(inputValue.value)) {// 获取所有节点const containerAllNode = container.childNodes;console.log(containerAllNode);// 用于保存找到的节点findNode.value = [];for (let i = 0; i < containerAllNode.length; i++) {// 遍历查询节点if (containerAllNode[i].textContent?.includes(inputValue.value)) {findNode.value.push(containerAllNode[i]);}}// 默认选中第一个if (findNode.value && findNode.value.length > 0) {index.value = 0;for (let j = 0; j < findNode.value.length; j++) {findNode.value[j].classList.add('abc');}setSelect(0);}} else {ElMessage.warning('未匹配到');}
};const previous = () => {if (index.value > 0) {index.value -= 1;} else {index.value = findNode.value.length - 1;}setSelect(index.value);
};const next = () => {if (index.value < findNode.value.length - 1) {index.value += 1;} else {index.value = 0;}setSelect(index.value);
};const setSelect = (index) => {const range = document.createRange();console.log(findNode.value[index]);range.selectNodeContents(findNode.value[index]);const selection = window.getSelection();selection?.removeAllRanges();selection?.addRange(range);
};</script>
<style lang="scss" scoped>
.container {width: 400px;height: 200px;margin-left: 100px;border: 1px solid red;::selection {background: #ff9632;}
}.abc {background-color: #ff0;
}
</style>

在这里插入图片描述

如果想实现只选中输入的文字,可以看 设置开始截止位置选中 这块内容,找到文字对应的起始位置和结束位置

局限

  • ctrl + f 搜索不是基于文本选中实现的,从下面的图片可以看出来
  • 如果真要实现类似浏览器的搜索功能是很复杂的,需要判断节点的类型,文字在哪一个节点里面;但是如果节点类型固定的话,还是可以简单试试

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_5566.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

F1C100S rt-smart 内核移植(二)

前言 本篇的内容进入了rt-smart内核的C语言世界,因此会同时涉及到较多的.c文件,需要读者对rt-smart内核有基本的认识,至少需要大致了解内核的文件结构。 在上一章节中,我们从启动汇编start_gcc.S进入了内核入口rtthread_startup,该内核入口函数位于./kernel/src/component…

linux 增加swap分区容量 --文件方式

背景:用笔记本做openstack测试时,由于需要同时开启多台虚拟机且每台内存要求8G以上,笔记本硬件已无法满足,故通过增加swap的方式处理操作 一、查看扩容前swap分区容量free -h 二、扩容 由于原来系统有3.9G,所以增加4.1G即可 1、创建swap扩容文件cd /tmp dd if=/dev/zero o…

【web-渗透测试方法】(15.6)测试基于输入的漏洞

目录 一、测试基于输入的漏洞 1.1、模糊测试所有清求参数 1.2、测试SQL注入 1.3、测试XSS和其他响应注入 确定反射型请求参数 测试反射型XSS 测试HTTP消息头注入 测试任意重定向 测试存储型攻击 1.4、测试OS命令注入 1.5、测试路径遍历 1.6、测试脚本注入 1.7、测…

windows系统 python3.6(Anaconda3)安装对应版本 torch、torchvision

一、官网下载 .whl 文件 https://download.pytorch.org/whl/torch_stable.html二、使用pip命令安装 打开你的anaconda,选择对应虚拟环境终端,进入刚才下载 .whl 文件的目录下,输入以下命令: install 后面的就是你的文件名,出现successful就是成功了。 pip install torch-1…

VUE3实战一之项目搭建

VUE3实战一之项目搭建1. 项目初始化1.1. 环境要求1.2. 创建VUE项目-基于vite1.3. 项目初始化2. 项目配置2.1. 基本配置修改iconTitle配置jsconfig.json2.2. 项目目录结构划分删除自带的项目按照常用的目录划分2.3. css样式重置reset.csscommon.cssindex.css3. 路由配置3.1. rou…

Pycharm生成allure报告报错--allure不是内部或外部命令,也不是可运行的程序 或批处理文件

问题: allure报错:‘allure’ 不是内部或外部命令,也不是可运行的程序 或批处理文件截图: 解决方法: 1.安装JDK(版本1.8+),配置环境变量 此处不展示过程,成功的后进入cmd java-version验证 2.下载Allure 下载网址: https://repo.maven.apache.org/mav…

20201330马榕辰第一,二章学习笔记

第一章:一.知识点归纳: 第一章前半部分重在介绍课程和书本的基本情况,包括Unix / Linux的历史,其各种发行版,我了解到了一些基本情况。 后半部分主要是 Linux的使用,Linux的启动过程,Unix/Linux文件系统组织、文件类型和常用的Unix/Linux命令,Linux系统的一些系统管理…

20201306吴龙灿学习笔记

一、知识点归纳: 第一章:引言 主要内容: 第一章是本书的引子,因为本书意在让我们学会Unix以及Linux相关只是,在高级语言的基础上进一步学习创造编程平台的基本语言,让我们学会硬件设备怎么样跟我们所熟知的软件设备取得联系。第一章讲述了我们如何利用本书学好系统编程,…

第二章 操作系统基本原理(操作系统知识)

一:操作系统概述 二:进程管理 PV操作与信号量的处理相关,P表示通过的意思,V表示释放的意思。 三:存储管理四:文件管理五:作业管理六:设备管理

opencv入门四

目录鼠标操作与响应图像像素归一化类型转换图像放缩插值鼠标操作与响应 static void on_draw(int event, int x, int y, int flags, void* userobj) {Mat image *(Mat*)userobj;if (event EVENT_LBUTTONDOWN) {//鼠标点击时 sp.x x;sp.y y;std::cout << "star…

预科知识1-MarkDown语法

MarkDown语法的基本操作markdown 标题 方法:#(几个)+空格+内容 三级标题 四级标题 字体 方法:加粗(2个星号 内容 2个星号) 斜体(1个星号 内容 1个星号) 加粗斜体(3个星号 内容 3个星号) 删除线(2个波浪 内容 2个波浪) hello world hello world …

在线教育项目【前端路由和Ajax实现分析与后端连接分析】

目录 1&#xff0c;前端路由实现分析 1.1&#xff1a;入口文件中调用路由 1.2&#xff1a;定义路由模块 1.3&#xff1a;编写路由模块文件 1.3.1&#xff1a;配置一个或者多个子路由 1.3.2&#xff1a;编写教师路由对应的文件 2&#xff0c;后端接口分析&#xff08;与后…

查询数字的最邻近

这道题目要用二分+桶排的方式解决 函数: l~r找v c:靠左/右(‘l’/‘r’) 靠左和靠右用STL函数二分就行,这里讲一下思路,二分出最靠左/右的v值(but二维,在but[v][0~len]区间二分)再判断是否在区间内在区间内输出but[v][a](a为二分的答案)否则输出-1。 最后再考虑一下需要…

注解Annotation

注解是一种引用数据类型,重点掌握Deprecated(表示已过时),Override(表示重写)。 元注解是用来标注注解类型的注解如Target(用来标注注解可以出现在哪些位置)、Retention(用来标注最终保存到哪里)。 package com.javastudy.example13;import java.lang.annotation.Ann…

计算机毕业设计php+vue基于微信小程序的员工宿舍报修系统

项目介绍 随着信息技术和网络技术的飞速发展&#xff0c;人类已进入全新信息化时代&#xff0c;传统管理技术已无法高效&#xff0c;便捷地管理信息。为了迎合时代需求&#xff0c;优化管理效率&#xff0c;各种各样的管理系统应运而生&#xff0c;各行各业相继进入信息管理时…

神奇的卡尔曼滤波,目标追踪的福音

前言 卡尔曼滤波算法由匈牙利数学家Kalman提出&#xff0c;主要基于线性系统提出。这里我们将其用于汽车跟踪&#xff0c;并对其基本原理进行介绍。 神奇的卡尔曼滤波&#xff0c;目标追踪的福音 1. 背景知识 1.1 时间序列模型 1.2. 滤波 1.3. 线性动态系统 2. 卡尔曼滤波…

python生成PDF报告

如何使用Python制作pdf文档&#xff1f; PDF报告生成软件开发&#xff08;学习记录&#xff09; Python生成图文并茂的PDF报告 官方用户手册 字体下载注册问题 在windows找到字体文件&#xff1a;C:\Windows\Fonts 在你的python环境引入字体 D:\devementtool\Anaconda3-202…

Java并发 JUC工具类:Semaphore详解

文章目录Semaphore源码分析类的继承关系类的内部类类的内部类 - Sync类类的内部类 - NonfairSync类类的内部类 - FairSync类类的属性类的构造函数核心函数分析 - acquire函数核心函数分析 - release函数Semaphore 示例更深入理解单独使用Semaphore是不会使用到AQS的条件队列的场…

USB4 V2.0即将发布,速度高达80Gbps

关注星标公众号&#xff0c;不错过精彩内容作者 | strongerHuang微信公众号 | strongerHuang2019年3月初&#xff0c;USB-IF组织官方宣布了下一代 USB4.2019年9月3日&#xff0c;USB-IF组织正式发布 USB4(现在称USB4 V1.0)规范。最近&#xff0c;也就是2022年9月1日&#xff0c…

推荐系统中的特征工程

摘要&#xff1a;深度学习时期&#xff0c;与CV、语音、NLP领域不同&#xff0c;搜推广场景下特征工程仍然对业务效果具有很大的影响&#xff0c;并且占据了算法工程师的很多精力。数据决定了效果的上限&#xff0c;算法只能决定逼近上限的程度&#xff0c;而特征工程则是数据与…