1. 程式人生 > 其它 >基於uni-app的通用搜索元件(歷史記錄,app語音輸入,搜尋推薦)解析 zy-search

基於uni-app的通用搜索元件(歷史記錄,app語音輸入,搜尋推薦)解析 zy-search

基於uni-app的通用搜索元件(歷史記錄,app語音輸入,搜尋推薦)解析 zy-search

一個通用的搜尋元件,包含搜尋歷史記錄,語音輸入,搜尋推薦功能

外掛地址:https://ext.dcloud.net.cn/plugin?id=512

外掛內容:



<template name="zy-search">
	<view>
		<view class="search">
			<!-- 執行在app端的程式碼 -->
			<!-- #ifdef APP-PLUS --> 
				<image src="../../static/zy-search/voice.svg" mode="aspectFit" @click="startRecognize()" class="voice-icon"></image>
			<!-- #endif -->
			<template v-if="isFocus">
				<input maxlength="20" focus type="text" value="" confirm-type="search" @confirm="searchStart()" placeholder="請輸入關鍵詞搜尋" v-model.trim="searchText"/>
			</template>
			<template v-else>
				<input maxlength="20" type="text" value="" confirm-type="search" @confirm="searchStart()" placeholder="請輸入關鍵詞搜尋" v-model.trim="searchText"/>
			</template>
			<image src="../../static/zy-search/search.svg" mode="aspectFit" @click="searchStart()" class="search-icon"></image>
		</view>
		<view :class="'s-' + theme" v-if="hList.length > 0">
			<view class="header">
				歷史記錄
				<image src="../../static/zy-search/delete.svg" mode="aspectFit" @click="delhistory"></image>
			</view>
			<view class="list">
				<view v-for="(item,index) in hList" :key="index" @click="keywordsClick(item)">{{item}}</view>
			</view>
		</view>
		<view :class="'wanted-' + theme" v-if="showWant">
			<view class="header">猜你想搜的</view>
			<view class="list">
				<view v-for="(item,index) in hotList" :key="index" @click="keywordsClick(item)">{{item}}</view>
			</view>
		</view>
	</view>
</template>

<script>
	export default{
		name:"zy-search",
		props:{
			isFocus:{	//是否自動獲取焦點
				type: Boolean,
				default: false
			},
			theme:{	//選擇塊級顯示還是圓形顯示
				type: String,
				default: 'block'
			},
			showWant:{	//是否展示推薦選單
				type: Boolean,
				default: false
			},
			hotList: { //推薦列表資料
				type: Array,
				default () {
					return []
				}
			},
			speechEngine: { //語音引擎=>訊飛:iFly,百度:'baidu'
				type: String,
				default: 'baidu'
			}
		},
		data() {
			return {
				searchText:'',								//搜尋關鍵詞
				hList:uni.getStorageSync('search_cache')		//歷史記錄
			};
		},
		methods: {
			//觸發搜尋  並加入歷史記錄
			searchStart: function() {	
				let _this = this;
				// 判斷輸入值為空的情況
				if (_this.searchText == '') {
					uni.showToast({
						title: '請輸入關鍵字',
						icon: 'none',
						duration: 1000
					});
				}else{
					// 通知父元件進行搜尋
					_this.$emit('getSearchText', _this.searchText);
					// 從本地快取中非同步獲取指定 key 對應的內容。
					uni.getStorage({
						key:'search_cache',
						success(res){
							let list = res.data;
							if(list.length > 5){
							// 如果陣列的長度大於5
								// 迴圈該陣列
								for(let item of list){
									// 如果陣列中有一項和當前輸入框中輸入的值相等的話,終止操作流程
									if(item == _this.searchText){
										return;
									}
								}
								// 刪除陣列最後一項
								list.pop();
								// 在陣列最前面增加一項
								list.unshift(_this.searchText);
							}else{
							// 如果陣列的長度小於5
								// 迴圈該陣列
								for(let item of list){
									// 如果陣列中有一項和當前輸入框中輸入的值相等的話,終止操作流程
									if(item == _this.searchText){
										return;
									}
								}
								// 在陣列最前面增加一項
								list.unshift(_this.searchText);
							}
							// 將當前新陣列賦值給列表上顯示
							_this.hList = list;
							// 向本地快取中非同步儲存指定 key 對應的內容。
							uni.setStorage({
								key: 'search_cache',
								data: _this.hList
							});
						},
						fail() {
							// 如果 從本地快取中非同步獲取指定 key 對應的內容   失敗
							// 清空列表上顯示的陣列
							_this.hList = [];
							// 將當前輸入的值給列表上顯示的陣列
							_this.hList.push(_this.searchText);
							// 向本地快取中非同步儲存指定 key 對應的內容。
							uni.setStorage({
								key: 'search_cache',
								data: _this.hList
							});
							// 通知父元件進行搜尋  (這裡的搜尋多餘了)
							_this.$emit('getSearchText', _this.searchText);
						}
					})
				}
			},
   			// 關鍵詞點選的事件 關鍵詞搜尋與歷史搜尋	
			keywordsClick (item) {
				// 將點選的關鍵詞內容賦值給搜尋的變數
				this.searchText = item;
				//觸發搜尋事件
				this.searchStart();
			},
			//清空歷史記錄
			delhistory () {		
				this.hList = [];
				uni.setStorage({
					key: 'search_cache',
					data: []
				});
			},
			//語音輸入
			startRecognize: function() {	
				let _this = this;
				let options = {};
				// /語音引擎=>訊飛:iFly,百度:'baidu'  父級傳入的 預設baidu
				options.engine = _this.speechEngine;
				// 是否需要標點符號 
				options.punctuation = false; 
				// 語音識別超時時間
				options.timeout = 10 * 1000; 
				// 啟動語音識別
				// 啟動語音識別時呼叫,當語音識別成功後通過successCallback回撥返回識別出文本內容,呼叫語音識別失敗則通過errorCallback回撥返回。
				// plus.speech.startRecognize( options, successCB, errorCB );
				// options: ( SpeechRecognizeOption ) 必選 語音識別引數,用於控制語音引擎的各種技術引數
				// successCB: ( RecognitionSuccessCallback ) 可選 語音識別成功回撥
				// 當語音識別引擎識別資料成功時的回撥函式,並返回識別出的文字內容。
				// errorCB: ( RecognitionErrorCallback ) 可選 語音識別失敗時的回撥函式
				// 當語音識別引擎識別資料失敗時的回撥函式,並返回失敗的錯誤資訊。
				plus.speech.startRecognize(options, function(s) {
					// 將語言識別到的內容拼接上輸入框中的內容賦值給輸入框
					_this.searchText = _this.searchText + s;
				});
			}
		}
	}
</script>

<style lang="less" scoped>
	.search{
		width: 640upx;
		margin: 30upx auto 0;
		position: relative;
		input{
			background-color: #F7F7F7;
			padding: 10upx 74upx;
			font-size: 28upx;
			border-radius: 50upx;
		}
		.voice-icon{
			width: 36upx;
			height: 36upx;
			padding: 16upx 20upx 16upx 0;
			position: absolute;
			left: 16upx;
			top: 4upx;
			z-index: 10;
		}
		.search-icon{
			width: 36upx;
			height: 36upx;
			padding: 16upx 20upx 16upx 0;
			position: absolute;
			right: 0;
			top: -2upx;
			z-index: 10;
		}
	}
	.s-block{
		margin-top: 30upx;
		.header{
			font-size: 32upx;
			padding: 30upx;
			position: relative;
			image{
				width: 36upx;
				height: 36upx;
				padding: 10upx;
				position: absolute;
				right: 40upx;
				top: 24upx;
			}
		}
		.list{
			display: flex;
			flex-wrap: wrap;
			view{
				width: 50%;
				color: #8A8A8A;
				font-size: 28upx;
				box-sizing: border-box;
				text-align: center;
				padding: 20upx 0;
				border-top: 2upx solid #FFF;
    			border-left: 2upx solid #FFF;
				overflow: hidden;
				white-space: nowrap;
				text-overflow: ellipsis;
				background-color: #F7F7F7;
			}
		}
	}
	.s-circle{
		margin-top: 30upx;
		.header{
			font-size: 32upx;
			padding: 30upx;
			border-bottom: 2upx solid #F9F9F9;
			position: relative;
			image{
				width: 36upx;
				height: 36upx;
				padding: 10upx;
				position: absolute;
				right: 40upx;
				top: 24upx;
			}
		}
		.list{
			display: flex;
			flex-wrap: wrap;
			padding: 0 30upx 20upx;
			view{
				padding: 8upx 30upx;
				margin: 20upx 30upx 0 0;
				font-size: 28upx;
				color: #8A8A8A;
				background-color: #F7F7F7;
				box-sizing: border-box;
				text-align: center;
				border-radius: 20upx;
			}
		}
	}
	.wanted-block{
		margin-top: 30upx;
		.header{
			font-size: 32upx;
			padding: 30upx;
		}
		.list{
			display: flex;
			flex-wrap: wrap;
			view{
				width: 50%;
				color: #8A8A8A;
				font-size: 28upx;
				box-sizing: border-box;
				text-align: center;
				padding: 20upx 0;
				border-top: 2upx solid #FFF;
				border-left: 2upx solid #FFF;
				background-color: #F7F7F7;
				overflow: hidden;
				white-space: nowrap;
				text-overflow: ellipsis;
			}
		}
	}
	.wanted-circle{
		margin-top: 30upx;
		.header{
			font-size: 32upx;
			padding: 30upx;
		}
		.list{
			display: flex;
			flex-wrap: wrap;
			padding: 0 30upx 20upx;
			view{
				padding: 8upx 30upx;
				margin: 20upx 30upx 0 0;
				font-size: 28upx;
				color: #8A8A8A;
				background-color: #F7F7F7;
				box-sizing: border-box;
				text-align: center;
				border-radius: 20upx;
			}
		}
	}
</style>

父元件使用:

<template>
	<view>
		<zy-search :is-focus="true" :theme="themeClass" :show-want="true" :hot-list="hotList" @getSearchText="getSearchText"></zy-search>
	</view>
</template>

<script>
import zySearch from './zy-search/zy-search.vue';
export default {
	components: {
		zySearch
	},
	data() {
		return {
			themeClass: 'circle',
			hotList: [] //初始化推薦列表
		};
	},
	onShow() {
		this.getHotSearch();
	},
	methods: {
		getHotSearch() {
			this.http('', {}).then(res => {
				if (res.success) {
					this.hotList = []
					res.data.hottest_list.map((item, index) => {
						this.hotList.push(item.content);
					});
				} else {
				}
			});
		},
		getSearchText(e) {
			uni.navigateTo({
				url: '/pagesCourse/index?keyWords=' + e
			});
		}
	}
};
</script>


語音識別相關內容參考:

https://www.dcloud.io/docs/api/zh_cn/speech.html