一、概述
先來看一下搜索效果
節流函數
首先,我們來理解一下:節流函數首先是節流,就是節約流量、內存的損耗,旨在提升性能,在高頻率頻發的事件中才會用到,比如:onresize,onmousemove,onscroll,oninput等事件中會用到節流函數;
實時查詢功能原理分析
所謂模糊查詢就是不需要用戶完整的輸入或者說全部輸入信息即可提供查詢服務,也就是用戶可以在邊輸入的同時邊看到提示的信息(其實是查詢出來匹配到的信息),百度的搜索功能就是很好的模糊查詢的例子;其實模糊查詢的原理就是給輸入框綁定oninput事件監聽用戶輸入情況,然后每次用戶只要在輸入框中輸入了信息就觸發事件進行查詢然后實時展示;原理很簡單,但是實現起來會有一些問題,我們可以想想,每輸入一個字符都會觸發事件,那如果我們需要輸入很長的信息呢,那查詢是不是就得觸發多次?ajax連續多次觸發,再加上如果我們的方法體中有操作DOM元素的方法,那么必然會給我們的瀏覽器進入假死甚至崩潰狀態;那么我們有沒有辦法來解決此類問題呢?答案是:有的;(不了解模糊查詢功能的同學可以出門右轉去百度首頁試一下搜索,給你5分鍾,我等你回來)
html視圖層代碼

<div> <div style="margin-top: 15px;"> <!-- 輸入框,綁定輸入框的值是變量input_value的值,然后對輸入框做了事件綁定keyup,在用戶輸入的時候會觸發--> <el-input placeholder="請輸入關鍵字" v-model="input_value" class="input-with-select" @keyup.native="throttle" ref="input"> <el-button slot="append" icon="el-icon-search"></el-button> </el-input> </div> <ul v-show="state"> <li v-for="(item,index) in list" :key="index" @click="handleInputClick(item)"> <span>{{item.title}}</span> </li> </ul> <div v-show="IsResultDisplayed" style="position:absolute;top: 70px"> <span>結果:</span> <span>{{ result }}</span> </div> </div>
從上述代碼中我們可以很明顯的看到DOM結構,就是一個輸入框,我們給輸入框加了ref屬性是為了方便我們后面操作DOM拿到輸入框的值(詳情可見ref和$refs的區別博文
www.cnblogs.com/dengyao-blo…),然后下面有一個ul列表,不過ul列表是判斷展示的;(至於為什么會用v-show而不是v-if,可以點擊鏈接查閱之前的博文
www.cnblogs.com/dengyao-blo…);
js數據邏輯層部分代碼

data() {
return {
input_value: "", // 搜索關鍵字
result:"", // 搜索結果
state: false,
statu: true,
// 示例數據
dataList: [
{id: "1001", title: "我的時代你的時代", content: "我的時代,你的時代(2021年胡一天、李一桐主演的電... - 百度百科"},
{id: "1002", title: "我的小確幸", content: "我的小確幸 - 百度百科"},
{id: "1103", title: "我的世界", content: "我的世界Minecraft中國版官方網站——你想玩的,...官方"},
{id: "1104", title: "我的世界基岩版", content: "我的世界基岩版1.16下載|我的世界基岩版 官方正式版v1.16 ..."},
{id: "1205", title: "科創版開戶條件", content: "開通科創板的條件有兩點:一是申請權限開通前20個交易日證券賬戶及"},
{id: "1206", title: "科創板股票開戶有什么條件", content: "科創板開戶條件:近20個交易日,賬戶平均資產(現金或者股票)達到50萬元"},
{id: "1307", title: "科創板股票交易規則", content: "科創板交易規則 - 百度知道"}
],
list: [],
IsResultDisplayed: false, // 結果是否顯示
}
},
methods: {
search() {
this.list = [];
//拿到當前input輸入框輸入的值
this.input_value = this.$refs.input.value;
//循環模擬數據的數組
this.dataList.map((msg) => {
//拿當前json的id、name、time去分別跟輸入的值進行比較
//indexOf 如果在檢索的字符串中沒有出現要找的值是會返回-1的,所以我們這里不等於-1就是假設輸入框的值在當前json里面找到的情況
if (msg.title.indexOf(this.input_value) != -1) {
//然后把當前json添加到list數組中
this.list.push(msg);
}
})
// 判斷展示ul列表,如果輸入了就展示沒輸入就不展示
if (this.input_value.length > 0) {
// this.state = true;
if (this.list.length > 0){
this.state = true;
}else {
this.state = false;
}
} else {
this.state = false;
}
},
js數據邏輯層代碼其實不難,主要就是給input綁定了keyup事件,在用戶輸入的時候會觸發search事件,用戶每輸入一個字符都會觸發一次;然后我們通過this.$refs.input.value來獲取輸入框當前的值並賦值給變量this.input_value,然后我們對this.input_value的長度進行判斷來實現對用戶是否輸入的判斷,如果用戶輸入了我們就把v-show綁定的值state賦值給true,反之則賦值為false;然后我們來用ES6的map方法來循環我們的dataList數組,dataList數組的數據是模擬后台接口數據,通過indexOf方法是否等於-1來進行判斷當前json里面是否有輸入框中輸入的數組,indexOf是javascript提供的操作字符串方法,調用方式:string.indexOf("要查詢的值"),如果str中沒有要查詢的值會返回我們-1,如果有會直接返回給我們查詢數據的當前下標;所以我們可以借助indexOf是否等於-1來進行判斷當前json中是否有我們要查詢的字符串;如果有的話,我們只需要把當前json添加到空數組list中即可,然后li綁定list展示;
到這里我們就可以看到我們要的模糊查詢功能已經實現了,但是我們上面講到模糊查詢會影響瀏覽器的性能,從控制台輸入的變量i的值可以看到我們的search方法已經被調用了8次,我們輸入的字符越長被調用的次數越多,如果方法里面有操作DOM的行為性能影響會更嚴重;所以我們現在來加上節流函數來看看:
//節流函數 throttle(){ //保持this的指向始終指向vue實例 var that=this; if(!that.statu){ return; } that.statu=false; setTimeout(function(){ console.log(new Date()); that.search(); that.statu=true; },1000) },
我們把我們寫的節流函數封裝在throttle里面執行,把@keyup綁定的點擊事件修改為throttle,當用戶輸入字符的時候觸發節流函數;效果圖如下:
我們可以從控制台很清晰的看到當我們使用節流函數的時候,當我們輸入了8個字符我們的方法只執行了兩次,並且執行時間是每隔一秒執行一次,一個方法執行2次肯定會比執行8次不管是在效率還是在性能方面都會是比較大的提升,用了節流函數之后相對上面沒用的節流函數來說,我們極大的實現了性能提升、優化,所以在高頻率觸發的事件中我們是可以建議用節流函數來進行控制和解決問題的;
test1.vue完整代碼如下:

<template> <div> <div style="margin-top: 15px;"> <!-- 輸入框,綁定輸入框的值是變量input_value的值,然后對輸入框做了事件綁定keyup,在用戶輸入的時候會觸發--> <el-input placeholder="請輸入關鍵字" v-model="input_value" class="input-with-select" @keyup.native="throttle" ref="input"> <el-button slot="append" icon="el-icon-search"></el-button> </el-input> </div> <ul v-show="state"> <li v-for="(item,index) in list" :key="index" @click="handleInputClick(item)"> <span>{{item.title}}</span> </li> </ul> <div v-show="IsResultDisplayed" style="position:absolute;top: 70px"> <span>結果:</span> <span>{{ result }}</span> </div> </div> </template> <script> export default { name: "test1", data() { return { input_value: "", // 搜索關鍵字 result:"", // 搜索結果 state: false, statu: true, // 示例數據 dataList: [ {id: "1001", title: "我的時代你的時代", content: "我的時代,你的時代(2021年胡一天、李一桐主演的電... - 百度百科"}, {id: "1002", title: "我的小確幸", content: "我的小確幸 - 百度百科"}, {id: "1103", title: "我的世界", content: "我的世界Minecraft中國版官方網站——你想玩的,...官方"}, {id: "1104", title: "我的世界基岩版", content: "我的世界基岩版1.16下載|我的世界基岩版 官方正式版v1.16 ..."}, {id: "1205", title: "科創版開戶條件", content: "開通科創板的條件有兩點:一是申請權限開通前20個交易日證券賬戶及"}, {id: "1206", title: "科創板股票開戶有什么條件", content: "科創板開戶條件:近20個交易日,賬戶平均資產(現金或者股票)達到50萬元"}, {id: "1307", title: "科創板股票交易規則", content: "科創板交易規則 - 百度知道"} ], list: [], IsResultDisplayed: false, // 結果是否顯示 } }, methods: { search() { this.list = []; //拿到當前input輸入框輸入的值 this.input_value = this.$refs.input.value; //循環模擬數據的數組 this.dataList.map((msg) => { //拿當前json的id、name、time去分別跟輸入的值進行比較 //indexOf 如果在檢索的字符串中沒有出現要找的值是會返回-1的,所以我們這里不等於-1就是假設輸入框的值在當前json里面找到的情況 if (msg.title.indexOf(this.input_value) != -1) { //然后把當前json添加到list數組中 this.list.push(msg); } }) // 判斷展示ul列表,如果輸入了就展示沒輸入就不展示 if (this.input_value.length > 0) { // this.state = true; if (this.list.length > 0){ this.state = true; }else { this.state = false; } } else { this.state = false; } }, //節流函數 throttle(){ //保持this的指向始終指向vue實例 var that=this; if(!that.statu){ return; } that.statu=false; setTimeout(function(){ console.log(new Date()); that.search(); that.statu=true; },1000) }, // 處理輸入點擊 handleInputClick(item){ this.input_value = item.title // 觸發正式查詢api操作 // this.$message.success('請求api,關鍵字'+item.title) // 清空關鍵字列表 this.list = [] // 顯示結果 this.IsResultDisplayed = true this.state = false this.result = item.content }, } } </script> <style scoped> ul { list-style: none; top: 0px; left: 0px; right: 0px; /*margin-left: -40px;*/ z-index: 999; /*overflow:auto;*/ position:relative; background-color: white; border: 2px solid #4e71f2!important; } ul :hover { cursor: pointer; /*background-color: #4c9fff;*/ color: #4e71f2; } li { list-style: none; top: 0px; left: 0px; right: 0px; padding: 0px 0px 8px; margin-left: -35px; } </style>
注意:運行前,確保正確安裝了ElementUI模塊。
運行成功后訪問頁面,和本文開頭一樣的效果的。
本文參考鏈接: