1. 防抖,回城-執行完成區間計時的那一次
觸發事件時開始計時,計時結束後執行事件處理。當計時未結束再次觸發事件,則清除計時器並重新計時。
思路:利用閉包,儲存回撥函式的計時器。判斷計時器是否存在,是-清除原計時器。在計時器內呼叫事件處理函式。
注意:這裡要搞清楚返回的匿名函式才是繫結的點選事件,而非 debounce 函式。匿名函式可以訪問父函式 debounce 宣告的 timer,每次呼叫匿名函式時,timer 的資料得到保留。
<button>防抖-計時器</button>
<button clss="notTimer">防抖-非計時器</button>
// 使用計時器
let btn = document.querySelector('button');
btn.addEventListener('click', debounce(handler));
// 事件處理函式
function handler(e) {
console.log(e); //未傳入引數時為undefine | 傳參後:PointerEvent
console.log(this); //未修改時為window | 修改this後:<button>防抖-計時器</button>
}
// 防抖函式
function debounce(fn) {
let timer;
// 新的事件會重新整理舊的事件,直到最後一件事等待1s後執行
return function (e) { // 返回作為回撥事件
let _this = this; // 注意:計時器的this只能指向window,用箭頭函式可繼承父業(es6)
if (timer) clearTimeout(timer);
timer = setTimeout(function () {
// 傳入函式呼叫,提高可複用性
fn.call(_this, e); //!修改this,得去記,得去用啊寶寶:call/bind/apply
}, 1000)
}
}
也可以用節流的計時方式。
// 不使用計時器
let btn1 = document.querySelector('.notTimer');
btn1.addEventListener('click', (function () {
let currTime = Date.now();
return function (e) {
let nowTime = Date.now();
if (nowTime - currTime < 3000) { // 時效內點選,重新整理計時器
currTime = nowTime;
return;
}
// 呼叫處理函式
console.log(e)
console.log(this)
currTime = nowTime; // 處理完畢,重新整理計時器
}
})())
2. 節流,cd-區間內只執行第一次,禁止執行第二次
觸發事件後立即執行事件處理,並開始計時,計時結束前,觸發事情不執行事件處理。(合理來說應該是直到第一個執行完畢,可以設定標記,執行完修改標記,作為鎖)
思路:記錄第一次執行呼叫的時間戳,超時才能執行下一次呼叫,並重置起始時間。
window.addEventListener('scroll', throttle(handlerScroll, 1000));
// 事件處理函式
function handlerScroll(e) {
console.log(e);
console.log(this);
}
// 節流函式
function throttle(fn, delay) {
let prevTime = Date.now();
return function (e) {
let nowTime = Date.now();
if (nowTime - prevTime > delay) { // 區間計時結束,執行處理,並重新整理起始時間
fn.apply(this, e);
prevTime = Date.now();
}
}
}