1. 防抖,回城-執行完成區間計時的那一次 觸發事件時開始計時,計時結束後執行事件處理。當計時未結束再次觸發事件,則清除計時器並重新計時。 思路:利用閉包,保存回調函數的計時器。判斷計時器是否存在,是-清除原計時器。在計時器內調用事件處理函數。 註意:這裡要搞清楚返回的匿名函數才是綁定的點擊事件,而 ...
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 (...arg) {
let nowTime = Date.now();
if (nowTime - prevTime > delay) { // 區間計時結束,執行處理,並刷新起始時間
fn.apply(this, arg);
prevTime = Date.now();
}
}
}