一、捕獲與冒泡模式
在討論addEventListener第三個參數之前,先來了解一下事件流,也就是事件的傳播方式。
事件流分為兩種:捕獲模式和冒泡模式。在捕獲模式中,事件從最外層的節點開始傳播,一直傳遞到最底層的節點;而冒泡模式則恰好相反,從最底層的節點開始傳播,逐漸向外傳遞,到最後傳遞到最外層的節點。
瀏覽器對事件流的處理分為三個階段:
1. 捕獲階段
2. 目標階段
3. 冒泡階段
捕獲階段是從document對象到觸發事件的最外層元素,目標階段是事件傳播到目標元素,冒泡階段是從目標元素到最外層元素。
在addEventListener中,第三個參數就是用來指定事件模式的,默認值為false,表示使用冒泡模式。如果將其設置為true,則表示使用捕獲模式。
// 冒泡模式
document.getElementById('example').addEventListener('click', function() {
console.log('我是來自 example 的點擊事件!');
});
// 捕獲模式
document.getElementById('example').addEventListener('click', function() {
console.log('我是來自 example 的點擊事件!');
}, true);
二、事件委託
事件委託是指利用事件機制,將一個父元素的事件處理程序註冊到子元素中,使得子元素在觸發事件時,可以執行父元素的事件處理程序。
這種編程方式的好處在於,可以減少事件程序的數量,提高頁面性能,並且可以方便地動態添加或刪除子元素,而不需要重新綁定事件處理程序。
實現事件委託的關鍵在於,可以通過事件傳播機制,將子元素的事件傳遞到父元素上。在這個過程中,可以通過第三個參數來控制事件的傳播方式。
以ul元素為父元素,li元素為子元素為例:
// 普通方式註冊事件處理程序
var lis = document.getElementsByTagName('li');
for (var i = 0; i < lis.length; i++) {
lis[i].addEventListener('click', function() {
console.log('我是來自' + this.innerText + '的點擊事件!');
});
}
// 事件委託方式註冊事件處理程序
document.querySelector('ul').addEventListener('click', function(event) {
if (event.target.tagName.toLowerCase() === 'li') {
console.log('我是來自' + event.target.innerText + '的點擊事件!');
}
});
可以看到,事件委託可以減少事件處理程序的數量,也可以方便地動態添加或刪除子元素。
三、事件綁定與解綁
addEventListener除了可以進行事件註冊外,也可以通過removeEventListener方法來進行解綁。removeEventListener需要傳入相同的事件類型、回調函數以及可選的useCapture參數,才能解綁之前相同的listener。
var triggerBtn = document.getElementById('trigger');
function clickEvent() {
console.log('按鈕被點擊了!');
}
// 綁定事件處理程序
triggerBtn.addEventListener('click', clickEvent);
// 解綁事件處理程序
triggerBtn.removeEventListener('click', clickEvent);
四、一次性事件綁定
有時候我們需要在某個事件觸發後,執行完事件處理程序後,解除事件綁定。由於removeEventListener需要了解之前綁定的listener函數,所以無法實現一次性解綁。不過可以藉助匿名函數實現一次性事件綁定。
// 綁定事件處理程序
document.getElementById('example').addEventListener('click', function() {
console.log('我是一次性的事件處理程序!');
document.getElementById('example').removeEventListener('click', arguments.callee);
});
在回調函數內部使用arguments.callee,指向了該函數本身,從而達到了一次性的效果。
五、多次事件觸發的節流和防抖
事件節流和防抖都是為了解決事件頻繁觸發而導致性能問題的問題,事件節流和防抖的本質是一樣的,都是通過降低事件觸發頻率,從而提升性能。
5.1 節流
事件節流的本質是使用setTimeout,實現“定時觸發”。它的實現方式是,第一次觸發事件立即執行事件處理程序,然後在一定時間內不管事件觸發了多少次,都不再執行事件處理程序,直到時間到了之後,才再次執行事件處理程序。
function throttle(fn, delay) {
let timer = null;
return function() {
let args = arguments;
let that = this;
if (!timer) {
timer = setTimeout(function() {
fn.apply(that, args);
timer = null;
}, delay);
}
};
}
// 用法
document.getElementById('example').addEventListener('click', throttle(function() {
console.log('我是通過節流方式處理的點擊事件!');
}, 1000));
5.2 防抖
事件防抖的本質是使用setTimeout,實現“延遲觸發”。它的實現方式是,事件觸發後,等待一定時間,如果在這段時間內沒有再次觸發事件,就執行事件處理程序,否則,重新開始計時。
function debounce(fn, delay) {
let timer = null;
return function() {
let args = arguments;
let that = this;
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(function() {
fn.apply(that, args);
timer = null;
}, delay);
};
}
// 用法
document.getElementById('example').addEventListener('click', debounce(function() {
console.log('我是通過防抖方式處理的點擊事件!');
}, 1000));
六、總結
在日常的開發工作中,我們經常需要為元素添加各種事件處理程序,而利用addEventListener提供的第三個參數,可以實現捕獲和冒泡模式的控制、事件委託、事件綁定和解綁、一次性事件綁定、事件節流和防抖等功能,實現更靈活、高效的事件管理。
原創文章,作者:HIDXL,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/333956.html