目录
ps:如有问题或是需要改正的地方可以发在评论区,我会及时改正回应。
问题:
搜索关键字,搜索到的内容标题与搜索的内容相同的字符串要高亮(显示其他颜色)。例如京东,淘宝,拼多多等等,这些软件的搜索功能。
难点:
如何把所有的字符串都替换掉,自己也百度了很多方法,但是他们写的都是大同小异,而且有一个共同的问题,就是只能高亮连词。什么意思呢? 如图所示。
实现思路:
首先循环搜索的字符串拿到所有的需要高亮的字符,再使用RegExp方法正则匹配所有相同字符,使用模板字符串给匹配到的字符加上高亮的样式,再使用replace方法将正则匹配到的字符替换为模板字符串处理后的高亮字符,返回处理后的数据,页面中用v-html渲染即可。
代码:
下面是本次demo的全部代码复制粘贴即可直接使用,代码中的搜索框使用的是uview2.0的的searce搜索,图标也是uview2.0的icon图标,附上地址。
ps:如要更改,只需要更换搜索框和icon的框架,事件名称不需要更改,这样就可以直接使用啦。
Search 搜索 | uView 2.0 - 全面兼容 nvue 的 uni-app 生态框架 - uni-app UI 框架 (uviewui.com)
Icon 图标 | uView 2.0 - 全面兼容 nvue 的 uni-app 生态框架 - uni-app UI 框架 (uviewui.com)
<template>
<!-- 搜索页面 -->
<view>
<!-- 搜索框 -->
<view class="p-lr-16 p-t-8">
<uni-search-bar @confirm="search" radius="24" placeholder="搜索" :cancelButton="false" bgColor="#f7f8fc"
:focus="true" v-model="keyword" @input="input" @clear="clear">
</uni-search-bar>
</view>
<view class="w-100p p-lr-12 p-t-16">
<!-- 搜索记录 -->
<view v-if="!searchResult.length && historyRecord.length>0">
<view class="flex-j">
<view class="color-0 font-16 m-b-12 bold">搜索历史</view>
<uni-icons @click="delRecord" custom-prefix="custom-icon" type="trash" size="14"></uni-icons>
</view>
<view class="ref1 w-100p wrap" :class=" showTwoLine ? 'hiden' : ''">
<block v-for="(item,index) in historyRecord" :key="item">
<view class="ref border-rds-2 h-30 p-lr-10 flex-c font-12 m-r-8 m-b-8"
:class="index===historyRecord.length - 1 ? 'noneMargin' : ''"
style="background: #f7f9fb; color: rgba(16, 16, 16, 1);" @click="searchHistoryRecord(item)">
{{item}}
</view>
</block>
<view v-if="showMoreIcon" class="w-30 h-30 flex-c m-l-8"
style="background: #f7f9fb; color: rgba(16, 16, 16, 1);" @click="showALL">
<uni-icons custom-prefix="custom-icon" :type=" showTwoLine ? 'bottom': 'top'"
size="18"></uni-icons>
</view>
</view>
</view>
<!-- 搜索内容 -->
<view v-else>
<block v-for="(item,index) in searchResult" :key="item.id">
<view class="name" style="color: rgba(102, 102, 102, 1)" v-html="item.txt" @click="toDetaile(item)">
</view>
<view class="line m-tb-12"></view>
</block>
</view>
</view>
</view>
</template>
<script>
import {
nextTick
} from "vue";
let that;
import {
searchAssociate
} from '@/common/api/index'
export default {
name: 'Search',
data() {
return {
keyword: '', //搜索关键字
historyRecord: [], //历史记录
searchResult: [], //搜索结果
showMoreIcon: false, //是否显示更多按钮
showTwoLine: false, //显示两行
clearId: null,
lineNum: 0,
}
},
onLoad() {
that = this
this.historyRecord = uni.getStorageSync('historyRecord') || []
//判断历史记录是否超过两行
setTimeout(() => {
this.allWidth()
}, 300)
},
methods: {
// 跳转搜索详情
toDetaile(item) {
let replaceReg = new RegExp('<span style="color: #333333; font-weight: 700; font-size: 28rpx">', "ig");
let title = item.txt.replace(replaceReg, '');
let replaceRegTwo = new RegExp('</span>', "ig")
let title1 = title.replace(replaceRegTwo, '')
this.toPageParams('/sub/pages/searchResult/searchResult', { keyword:title1 })
this.search({ value: title1 })
},
// 关键字高亮
changeColor(arr) {
arr.map((item, index) => {
if (this.keyword) {
let str = this.keyword
for (var i = 0; i < str.length; i++) {
let replaceReg = new RegExp(str[i], "ig");
let replaceString =
`<span style="color: #333333; font-weight: 700; font-size: 28rpx">${str[i]}</span>`;
arr[index].txt = item.txt.replace(replaceReg, replaceString);
}
}
});
return arr;
},
// 输入框内容改变
input(e) {
clearInterval(this.clearId)
if (e.length > 0) {
this.clearId = setTimeout(() => {
this.searchPort()
}, 500)
} else {
this.searchResult = []
}
},
// 搜索框右侧清除图标按钮
clear() {
this.keyword = ''
this.searchResult = []
},
// 0联想 1搜索
searchPort() {
// 联想
searchAssociate({
content: this.keyword
}).then(res => {
this.searchResult = this.changeColor(res.data);
})
},
// 搜索框回车事件
search(e) {
if (e.value.trim() != '') {
if (this.historyRecord.indexOf(e.value) < 0) {
this.historyRecord.unshift(e.value)
let arr = this.historyRecord.concat(uni.getStorageSync('historyRecord'))
uni.setStorageSync('historyRecord', [...new Set(arr)])
}
if (uni.getStorageSync('historyRecord').length > 19) {
this.historyRecord.pop()
uni.setStorageSync('historyRecord', uni.getStorageSync('historyRecord').pop())
}
uni.setStorageSync('historyRecord', this.historyRecord)
this.allWidth()
this.toPageParams('/sub/pages/searchResult/searchResult', { keyword:this.keyword })
} else {
uni.showToast({
title: '请输入搜索内容',
icon: "none"
})
}
},
// 点击历史记录进行搜索
searchHistoryRecord(item) {
this.keyword = item
uni.navigateTo({
url: `/sub/pages/searchResult/searchResult?keyword=${item}`
})
},
// 删除历史记录
delRecord() {
uni.showModal({
title: '提示',
content: '删除后不可恢复',
success: function(res) {
if (res.confirm) {
that.historyRecord = []
that.showTwoLine = false
that.showMoreIcon = false
uni.removeStorage({
key: 'historyRecord'
})
uni.showToast({
title: '删除成功'
})
}
}
});
},
// 显示所有记录
showALL() {
let type = uni.getStorageSync('historyRecord').length == this.historyRecord.length
if (!type) {
this.showTwoLine = false
this.historyRecord = uni.getStorageSync('historyRecord')
} else {
this.allWidth()
}
},
// 判断搜索记录总长度
allWidth() {
this.lineNum = 0
this.$nextTick(() => {
uni.createSelectorQuery().in(this).selectAll('.ref').boundingClientRect(data => {
let firstItemLeft = 0
if (data.length > 0) {
firstItemLeft = data[0].left
}
for (let i = 0; i < data.length; i++) {
let item = data[i]
if (item.left === firstItemLeft) {
this.lineNum++
if (this.lineNum >= 3) {
this.showTwoLine = true
this.showMoreIcon = true
return this.historyRecord = this.historyRecord.slice(0, data[i - 1].right < 300 ? i : i - 1)
}
}
}
}).exec()
})
}
},
}
</script>
<style lang="scss">
page {
background-color: #fff;
}
.uni-searchbar {
padding: 0 !important;
}
.uni-searchbar__box {
height: 32px;
padding: 0;
}
.bold {
font-weight: 700;
} .hiden {
overflow: hidden;
height: 140rpx !important;
}
.wrap {
display: flex;
flex-wrap: wrap;
}
.noneMargin {
margin-right: 0 !important;
}
</style>