一、遇到的問題
實際工作中,我們經常性的會通過監聽某些事件完成對應的需求,比如:
- 通過監聽 scroll 事件,檢測滾動位置,根據滾動位置顯示返回頂部按鈕
- 通過監聽 resize 事件,對某些自適應頁面調整DOM的渲染(通過CSS實現的自適應不再此范圍內)
- 通過監聽 keyup 事件,監聽文字輸入並調用接口進行模糊匹配
二、函數防抖
定義:多次觸發事件后,事件處理函數只執行一次,並且是在觸發操作結束時執行。
原理:對處理函數進行延時操作,若設定的延時到來之前,再次觸發事件,則清除上一次的延時操作定時器,重新定時。
let timer; window.onscroll = function () { if(timer){ clearTimeout(timer) } timer = setTimeout(function () { //滾動條位置 let scrollTop = document.body.scrollTop || document.documentElement.scrollTop; console.log('滾動條位置:' + scrollTop); timer = undefined; },200) }
函數封裝
/** * 防抖函數 * @param method 事件觸發的操作 * @param delay 多少毫秒內連續觸發事件,不會執行 * @returns {Function} */ function debounce(method,delay) { let timer = null; return function () { let self = this, args = arguments; timer && clearTimeout(timer); timer = setTimeout(function () { method.apply(self,args); },delay); } } window.onscroll = debounce(function () { let scrollTop = document.body.scrollTop || document.documentElement.scrollTop; console.log('滾動條位置:' + scrollTop); },200)
三、函數節流
定義:觸發函數事件后,短時間間隔內無法連續調用,只有上一次函數執行后,過了規定的時間間隔,才能進行下一次的函數調用。
原理:對處理函數進行延時操作,若設定的延時到來之前,再次觸發事件,則清除上一次的延時操作定時器,重新定時。
let startTime = Date.now(); //開始時間 let time = 500; //間隔時間 let timer; window.onscroll = function throttle(){ let currentTime = Date.now(); if(currentTime - startTime >= time){ let scrollTop = document.body.scrollTop || document.documentElement.scrollTop; console.log('滾動條位置:' + scrollTop); startTime = currentTime; }else{ clearTimeout(timer); timer = setTimeout(function () { throttle() }, 50); } }
函數封裝
/** * 節流函數 * @param method 事件觸發的操作 * @param mustRunDelay 間隔多少毫秒需要觸發一次事件 */ function throttle(method, mustRunDelay) { let timer, args = arguments, start; return function loop() { let self = this; let now = Date.now(); if(!start){ start = now; } if(timer){ clearTimeout(timer); } if(now - start >= mustRunDelay){ method.apply(self, args); start = now; }else { timer = setTimeout(function () { loop.apply(self, args); }, 50); } } } window.onscroll = throttle(function () { let scrollTop = document.body.scrollTop || document.documentElement.scrollTop; console.log('滾動條位置:' + scrollTop); },800)