uniapp 仿京东、淘宝、拼多多的搜索框,实现搜索关键字所有匹配到的关键字都高亮,复制即用。(uniapp实现搜索关键字高亮看这一篇就够啦)

        ​​​​​

目录

问题:

难点:

实现思路:

代码:

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>

ps:如有问题或是需要改正的地方可以发在评论区,我会及时改正回应。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值