查询文本demo说明
如上图,这个demo主要支持以下功能
- 在输入框中输入关键字,页面会根据关键字自动检索文本
- 完成检索后默认黄色高亮第一个匹配到的关键字,其余匹配到关键字灰色高亮,并展示出当前高亮关键词的序号和匹配到关键字的总数
- 通过上一个,下一个按钮或者up、down键盘,切换时黄色高亮新的关键字,更新当前关键词序号
- 下一个或上一个关键字没有在页面中,切换时自动调整滚动条,展示出下一个或上一个关键词
- 当前黄色高亮最后一个关键字,再点击下一个自动跳到文本第一个匹配的关键字;当前黄色高亮为第一个关键字,再点击上一个自动跳到文本最后一个匹配的关键字
关键实现步骤
- 利用正则表达式根据输入框输入的关键字将所有匹配到的关键字替换为灰色背景的span标签
brightenKeyword () {
this.allLightKeyWords = []
const Reg = new RegExp(this.keyWordInput, 'ig')
//将原文本匹配到的关键字全量替换为灰色背景的span标签
/*
.lightStyle{
color: #000;
background-color: #ccc;
}*/
this.lightStr = this.oriTexts.replace(Reg, '<span class="lightStyle">' + this.keyWordInput + '</span>')
this.allLightKeyWords = document.getElementsByClassName('lightStyle')
//获取替换后所有的元素并返回
return this.allLightKeyWords
},
- 默认将匹配到第一个关键字黄色高亮,并定位匹配关键字在文本窗口中的位置
async locationLightKeyWord () {
await this.brightenKeyword()
if (this.allLightKeyWords.length > 0) {
this.$nextTick(function () {
this.totalNum = this.allLightKeyWords.length
// 输入框输入关键字时处理高亮和滚动
this.allLightKeyWords['0'].className = 'lightStyle currentLightStyle'
document.getElementById('textArea').scrollTop = this.allLightKeyWords['0'].offsetTop - 75
})
}
},
- 处理上一个和下一个点击事件
preKeyWord () {
if (this.totalNum >= 1) {
this.preBtnDisable = false
if (this.currentNodeIndex === 0) {
this.currentNodeIndex = this.totalNum - 1
this.nowNum = this.currentNodeIndex + 1
} else {
this.currentNodeIndex = this.currentNodeIndex - 1
this.nowNum = this.currentNodeIndex + 1
}
this.changeCurrentKeyword()
} else {
this.preBtnDisable = true
}
},
nextKeyWord () {
if (this.totalNum >= 1) {
this.nextBtnDisable = false
if (this.currentNodeIndex === this.totalNum - 1) {
this.currentNodeIndex = 0
this.nowNum = this.currentNodeIndex + 1
} else {
this.currentNodeIndex = this.currentNodeIndex + 1
this.nowNum = this.currentNodeIndex + 1
}
this.changeCurrentKeyword()
} else {
this.nextBtnDisable = true
}
},
//黄色高亮当前关键字
changeCurrentKeyword () {
// 给当前关键字添加黄色高亮的类
this.allLightKeyWords[this.currentNodeIndex].className = 'lightStyle currentLightStyle'
//点击下一个时将原来黄色高亮的关键字回复为灰色高亮
if (this.allLightKeyWords[this.currentNodeIndex - 1]) {
this.allLightKeyWords[this.currentNodeIndex - 1].className = 'lightStyle'
}
//点击上一个时将原来黄色高亮的关键字回复为灰色高亮
if (this.allLightKeyWords[this.currentNodeIndex + 1]) {
this.allLightKeyWords[this.currentNodeIndex + 1].className = 'lightStyle'
}
// 调整窗口,使当前黄色高亮关键字在窗口的可视范围内
document.getElementById('textArea').scrollTop = this.allLightKeyWords[this.currentNodeIndex].offsetTop - 75
}
demo全量代码
以下为demo的全量代码,希望能帮助到你,如有不足随时欢迎大家交流沟通
<template>
<div class="main-box">
<el-col>
<el-col :span="16">
<el-input
label-width="240px"
placeholder="请输入关键字"
prefix-icon="el-icon-search"
v-model="keyWordInput"
@input="keyWordChange"
@keyup.down.native="nextKeyWord"
@keyup.up.native="preKeyWord"
@keyup.enter.native="nextKeyWord"
clearable/>
</el-col>
<el-col :span="4" class="right-button">
<span style="display:inline-block;width:20px">{{nowNum}}/{{totalNum}}</span>
<el-tooltip effect="dark" content="上一个" placement="top">
<el-button @click="preKeyWord" :disabled="preBtnDisable" icon="el-icon-arrow-up" circle type="text"></el-button>
</el-tooltip>
<el-tooltip effect="dark" content="下一个" placement="top">
<el-button @click="nextKeyWord" :disabled="nextBtnDisable" icon="el-icon-arrow-down" circle type="text"></el-button>
</el-tooltip>
</el-col>
</el-col>
<el-col id="textArea" class="scroller text-box" v-html="lightStr"></el-col>
</div>
</template>
<script>
export default {
name: 'test',
data () {
return {
keyWordInput: '',
lightStr: '',
oriTexts: '',
totalNum: 0,
nowNum: 0,
preBtnDisable: true,
nextBtnDisable: true,
currentNodeIndex: 0,
allLightKeyWords: []
}
},
watch: {
},
methods: {
preKeyWord () {
if (this.totalNum >= 1) {
this.preBtnDisable = false
if (this.currentNodeIndex === 0) {
this.currentNodeIndex = this.totalNum - 1
this.nowNum = this.currentNodeIndex + 1
} else {
this.currentNodeIndex = this.currentNodeIndex - 1
this.nowNum = this.currentNodeIndex + 1
}
this.changeCurrentKeyword()
} else {
this.preBtnDisable = true
}
},
nextKeyWord () {
if (this.totalNum >= 1) {
this.nextBtnDisable = false
if (this.currentNodeIndex === this.totalNum - 1) {
this.currentNodeIndex = 0
this.nowNum = this.currentNodeIndex + 1
} else {
this.currentNodeIndex = this.currentNodeIndex + 1
this.nowNum = this.currentNodeIndex + 1
}
this.changeCurrentKeyword()
} else {
this.nextBtnDisable = true
}
},
keyWordChange (value) {
this.keyWordInput = value
this.currentNodeIndex = 0
if (this.keyWordInput) {
this.locationLightKeyWord()
this.nowNum = 1
this.preBtnDisable = false
this.nextBtnDisable = false
} else {
this.nowNum = 0
this.totalNum = 0
this.preBtnDisable = true
this.nextBtnDisable = true
this.lightStr = this.oriTexts
}
},
brightenKeyword () {
this.allLightKeyWords = []
const Reg = new RegExp(this.keyWordInput, 'ig')
this.lightStr = this.oriTexts.replace(Reg, '<span class="lightStyle">' + this.keyWordInput + '</span>')
this.allLightKeyWords = document.getElementsByClassName('lightStyle')
return this.allLightKeyWords
},
async locationLightKeyWord () {
await this.brightenKeyword()
if (this.allLightKeyWords.length > 0) {
this.$nextTick(function () {
this.totalNum = this.allLightKeyWords.length
// 输入框输入关键字时处理高亮和滚动
this.allLightKeyWords['0'].className = 'lightStyle currentLightStyle'
document.getElementById('textArea').scrollTop = this.allLightKeyWords['0'].offsetTop - 75
})
}
},
changeCurrentKeyword () {
this.allLightKeyWords[this.currentNodeIndex].className = 'lightStyle currentLightStyle'
if (this.allLightKeyWords[this.currentNodeIndex - 1]) {
this.allLightKeyWords[this.currentNodeIndex - 1].className = 'lightStyle'
}
if (this.allLightKeyWords[this.currentNodeIndex + 1]) {
this.allLightKeyWords[this.currentNodeIndex + 1].className = 'lightStyle'
}
document.getElementById('textArea').scrollTop = this.allLightKeyWords[this.currentNodeIndex].offsetTop - 75
}
},
mounted () {
this.lightStr = this.oriTexts = `测试文本99测试文本测试文本测试文本测试文
本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本
测试文本测试文本测试文本测试文本测试文本测试文本1测试文本测试文本999测试文本测试文本测试文本测试文本测试文本
测试文本测试文本测试文本测试文本测试文本2测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本
测试文本测试文本测试文本测试文本3测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本
测试文本测试文本测试文本4测试文本测试9999文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本
测试文本测试文本5测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本
测试文本6测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本
测试文本测试文本测试文本测试文本测试文
本测试文本测试文本测试99文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本
测试文本测试文本测试文本测试文本测试文本测试文本1测试文本测试文本测试文本测试文本测试文本测试文本测试文本
测试文本测试文本测试文本测试文本测试文本2测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本
测试文本测试文本测试文本测试文本3测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本
测试文本测试文本测试文本4测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本
测试文本测试文本5测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本
测试文本6测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本
测试文本测试文本测试文本测试文本测试文
本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本
测试文本测试文本测试文本测试文本测试文本测试文本1测试文本测试文本测试文本测试文本测试文本测试文本测试文本
测试文本测试文本测试文本测试文本测试文本2测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本
测试文本测试文本测试文本测试文本3测试文本测试文本测试文本测试99文本测试文本测试文本测试文本测试文本测试文本
测试文本测试文本测试文本4测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本
测试文本测试文本5测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本
测试文本6测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本测试文本`
}
}
</script>
<style>
.lightStyle{
color: #000;
background-color: #ccc;
}
.currentLightStyle{
color: #000;
background-color: #e6a23c;
}
.main-box{
margin-top:20px;
margin-left:50px;
width:800px;
}
.right-button{
float:right;
margin-right:10px;
}
.text-box{
margin-top:10px;
height: 800px;
width:760px;
border:1px solid #c8c8c8;
overflow-y:auto;
padding:0px 6px;
font-size:20px
}
.scroller::-webkit-scrollbar {
width: 8px;
}
.scroller::-webkit-scrollbar-track {
background-color:#F5F5F5;
-webkit-border-radius: 2em;
-moz-border-radius: 2em;
border-radius:2em;
}
.scroller::-webkit-scrollbar-thumb {
background-color:#c8c8c8;
-webkit-border-radius: 2em;
-moz-border-radius: 2em;
border-radius:2em;
}
</style>
补充
如果有朋友需要处理动态加载文本内容;请结合上一篇文章"vue实用demo通过滚动条滚动事件动态加载内容动态请求后台数据"