在网上冲浪的过程中,我们会发现在浏览器输入关键词进行检索后,搜索到的关键字都会高亮匹配。下面我将围绕这个场景来分享:
一.演示
二.实现思路
这样的需求我选择了使用正则表达式,首先,用户在搜索框中输入关键词。我们需要定义变量来接收这个关键词,同时在后端完成模糊匹配查询,将查询到的数据用正则表达式匹配替换,后端响应数据中出现的关键词嵌入带特殊样式(如颜色,背景)的标签。如用户输入"通义千问",从后端查询到的数据是{"code": 200, "msg": success, "data": "通义千问是阿里训练出的一款大模型"}。那么按照前面的思路,前端渲染出来的应该是"<span style="color: #FF8C00;">通义千问</span>是阿里训练出的一款大模型",如果想对span标签设置宽高还需修改span为行内块布局。
三.编码
在Vue3 setup语法糖中:
<script setup lang="ts">
let page = ref<number>(1)
let pageSize = ref<number>(5)
let keyWord: string = ''
type paramsType = {
currentPage: number,
pageSize: number,
annex: string,
sort: string,
message: string,
}
const state = reactive({
data: [{
id: 1,
askerId: 1,
asker: role.role === 'NPC' ? npcStore.name : people.name,
title: '',
detail: '',
fileName: '',
annex: '',
thumbUp: 1,
liker: <string><unknown>[],
read: 1,
time: '',
}],
params: <paramsType>{
currentPage: page.value,
pageSize: pageSize.value,
annex: '综合',
sort: 'sortFromLargeToSmall',
message: ''
}
})
const getData = async (): Promise<Object[]> => {
let res = await request.get('/question/getQuestion', { params: state.params });
if (res.data.length < 5 && res.data.length > 0) {
disableOrNotBackward.value = true;
} else
disableOrNotBackward.value = false
state.data = res.data;
return state.data;
}
const search = async () => {
keyWord = state.params.message;
getData();
state.params.message = '';
}
const regExpText = (detail: string) => {
console.log('匹配内容: ' + keyWord);
let reg = new RegExp(keyWord, 'gi');
return detail.replace(reg, (match) => {
return `<span style="color: #FF9933;"> ${match} </span>`
})
}
</script>
<template>
<div class="contain">
<div class="search">
<div class="search-input">
<el-input v-model="state.params.message" size="normal" style="margin-top: 6px;" />
</div>
<div class="search-btn">
<el-button><i class="iconfont icon-sousuo" style="font-size: 27px;" @click="search()"></i></el-button>
</div>
</div>
<div class="main">
<div class="main-area">
<el-empty v-if="state.data.length === 0" description="暂无数据" />
<div v-for="(item, index) in state.data" :key="index" class="content-area">
<div class="word" @click="commentModel(item.id)">
<h3 v-html="regExpText(item.title)"></h3>
<div v-html="regExpText(item.detail)" class="detail"></div>
<div class="tag">
<span><i class="iconfont icon-eyes_line_b"></i>{{ item.read }}</span>
<span v-if="item.liker.includes(state.thumbUp.liker)" class="thumbUp"
@click.stop="revoke(item.id)"><i class="iconfont icon-dianzan"></i>{{
item.thumbUp }}</span>
<span v-else class="unThumbUp" @click.stop="thumbUp(item.id, item.askerId)"><i
class="iconfont icon-dianzan"></i>{{ item.thumbUp }}</span>
<span v-html="item.time" style="width: 99px; font-size: 13px; color: grey;"></span>
<div class="annex">
<el-tag v-if="item.annex != ''" v-for="Item in item.annex.split(', ')"
style="width: auto; margin-left: 9px; float: right;">{{ Item }}</el-tag>
<span v-if="item.hot >= 60"
style="color: #FF9900; width: auto; margin-left: 5px;">热门</span>
</div>
</div>
</div>
<div v-if="item.fileName != '' && item.fileName != null" class="image">
<img :src="getAssetURL(item.fileName)" width="66%"
style="margin-left: 33%; margin-top: 9%; border-radius: 5px;" />
</div>
</div>
</div>
</div>
</div>
</template>
【附】后端响应数据结构
四.总结
4.1 文本高亮匹配可以用正则表达式,对关键词进行全局匹配,匹配到的文本添加特殊样式完成高亮。