概念
防抖就是在事件觸發后等待n秒再執行對事件的邏輯處理函式,
在進行視窗的resize、scroll,輸入框內容校驗等操作時,如果事件處理函式呼叫的頻率無限制,會加重瀏覽器的負擔,導致用戶體驗非常糟糕,此時我們可以采用debounce(防抖)的方式來減少呼叫頻率,同時又不影響實際效果,
主要用到了setTimeout去延遲函式執行時間,但當事件觸發了很多次,對應也有很多處理函式在等待執行,而我們只需要事件在停止觸發后一段時間執行一次函式,所以,在事件觸發后,需要取消上次執行函式的定時器,
代碼
1.基礎版
/**
* 防抖函式,在事件觸發waitTime毫秒后執行func
* @param func 事件處理函式
* @param waitTime 觸發事件與執行處理函式的間隔
* @return {Function} 觸發事件呼叫的JS函式
*/
function debounce(func, waitTime) {
let timer = null; //定時器標識
return function() { //見代碼后解釋①
const context = this; //存盤this指標,用于系結setTimeout中的指標指向,這里指向這個函式的呼叫者,(如果setTimeout中使用箭頭函式,則無需存盤,直接用)
const args = arguments; //arguments為這個函式接收到的引數,通常為事件物件
if (timer) clearTimeout(timer); //清空上次的定時器,為什么能清空上次的?同代碼后解釋①
timer = setTimeout( //定時器
function() { return func.apply(context, args) }, //執行func函式,并且系結func函式內的this,以及傳引數args給func函式,
waitTime //執行func函式等待時間
);
}
}
/*
* 邏輯處理,e視情況需要
*/
function printToConsole(e) { //e,觸發的事件物件
console.log(e);
}
//start resize事件使用
window.onresize = debounce(printToConsole, 1000); //等號'=',先呼叫了debounce,回傳了匿名函式
//上面賦值給window.onresize的JS代碼是debounce里return的代碼
//即function() {const context = this; ......},
或
window.addEventListener('resize', debounce(printToConsole, 1000)());
//如果使用addEventListener,則需要手動在debounce后加個'()'去得到回傳的匿名函式
//end
解釋①:為什么return一個匿名函式?不用行不行?
確保事件觸發的是匿名函式,不會重新將timer置為null,同時,匿名函式是一個閉包,timer變數不會被回收,這樣,就能使用clearTimeout清空上次的定時器了,
不能?,在這里,timer會被置為null,清空不了上次的定時器,那樣就只是單純的將所有的邏輯處理函式異步延遲觸發了,(可以自己額外維護一個變數?),
2.在vue中的使用
當我們將防抖函式寫成上面的樣子時,如果需要對vue組件的change事件,watch進行防抖,那么可能就不適用了,如on-change事件:
<sg-input on-change='handleInputValueChange'></sg-input>
handleInputValueChange() {
console.log('hello, changsha!');
}
怎么對change事件的邏輯處理進行防抖限制呢?
我們知道,change事件呼叫的函式始終是匿名函式,而不是整個debounce函式,
所以我們先呼叫debounce并將匿名函式賦值給另一個函式,
methods: {
previewImageDebounce: debounce(this.printToConsole, 1000)
}
//this原因報錯 Uncaught TypeError: Cannot read property 'printToConsole' of undefined
這里改成將函式名傳到debounce中,在debounce中調用邏輯處理函式,如下:
使用:
methods: {
previewImageDebounce: debounce('printToConsole', 1000),
handleInputValueChange() {
this.previewImageDebounce();
}
}
改后的debounce:
/**
* 防抖函式,在事件觸發waitTime毫秒后執行func
* @param func 事件處理函式或者函式名
* @param waitTime 觸發與執行處理函式間隔
* @return {Function} 觸發事件呼叫的JS函式
*/
function debounce(func, waitTime) {
let timer = null;
return function() {
const args = arguments;
if (timer) clearTimeout(timer);
+ if (typeof func === 'function') {
+ timer = setTimeout(() => func.apply(this, args), waitTime);
+ } else if (typeof func === 'string') {
+ timer = setTimeout(() => this[func].apply(this, args), waitTime);
+ } else {
+ console.warn('事件處理邏輯未執行');
+ }
}
}
在vue中的使用來自:https://zhuanlan.zhihu.com/p/128055659
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/263841.html
標籤:其他
上一篇:vue常見指令
