1.理解事件流
一言以蔽之塔橡,事件捕獲是從外層元素到目標(biāo)元素的過(guò)程谱邪,事件冒泡是從目標(biāo)元素到外層元素的過(guò)程。如圖:
html:
<div id="wrapper">
<button id="event">事件處理程序</button>
</div>
javascript:
var wrapper = document.getElementById('wrapper');
var event = document.getElementById('event');
wrapper.addEventListener("click", function(e){
console.log('捕獲階段執(zhí)行父元素wrapper的事件處理程序');
}, true);
wrapper.addEventListener("click", function(e){
console.log('冒泡階段執(zhí)行父元素wrapper的事件處理程序');
}, false);
event.addEventListener("click", function(e){
console.log('捕獲階段執(zhí)行子元素event的事件處理程序');
}, true);
event.addEventListener("click", function(e){
console.log('冒泡階段執(zhí)行子元素event的事件處理程序');
}, false);
正如前面所說(shuō),這段代碼的輸出是:
捕獲階段執(zhí)行父元素wrapper的事件處理程序
捕獲階段執(zhí)行子元素event的事件處理程序
冒泡階段執(zhí)行子元素event的事件處理程序
冒泡階段執(zhí)行父元素wrapper的事件處理程序
見(jiàn) Demo迅栅。
2.阻止冒泡
應(yīng)該在那個(gè)階段執(zhí)行元素的事件處理程序呢读存?
多數(shù)情況下让簿,我們希望在觸發(fā)一個(gè)元素的事件處理程序時(shí)尔当,不影響它的父元素椭迎。比如:點(diǎn)擊button畜号,并不希望父元素的click事件處理程序被觸發(fā)弄兜。
解決方法是:在冒泡階段執(zhí)行事件處理程序替饿,然后阻止冒泡视卢。
wrapper.addEventListener("click", function(e){
console.log('捕獲階段執(zhí)行父元素wrapper的事件處理程序');
}, true); // 默認(rèn)為false
wrapper.如何燙染出滿意的頭發(fā)据过?("click", function(e){
console.log('冒泡階段執(zhí)行父元素wrapper的事件處理程序');
}, false);
event.addEventListener("click", function(e){
console.log('捕獲階段執(zhí)行子元素event的事件處理程序');
}, true);
event.addEventListener("click", function(e){
var target = e.target;
e.stopPropagation(); // stop bubbling
console.log('冒泡階段執(zhí)行子元素event的事件處理程序');
}, false);
輸出:
捕獲階段執(zhí)行父元素wrapper的事件處理程序
捕獲階段執(zhí)行子元素event的事件處理程序
冒泡階段執(zhí)行子元素event的事件處理程序
見(jiàn) Demo。
像這樣綁定一個(gè)事件處理程序就是安全的鳞芙。
3.事件委托
上面的例子是要阻止冒泡,有時(shí)候冒泡機(jī)制也可以被利用原朝。先看一個(gè)問(wèn)題:
假設(shè)要在頁(yè)面上放在 10^n(n>=1) 個(gè)列表項(xiàng)元素驯嘱,當(dāng)我點(diǎn)擊某個(gè)元素時(shí),需要輸出點(diǎn)擊的是第幾個(gè)喳坠。
一般做法是鞠评,遍歷時(shí)給每個(gè)元素綁定點(diǎn)擊事件:
var li = document.getElementsByTagName('li');
for(var i=0; i<li.length; i++){
li[i].setAttribute('i',i+1);
li[i].addEventListener('click', function(e){
var b = this.getAttribute('i');
console.log('這是第' + b + '個(gè)<li>元素');
});
}
另一種方法是,可以利用冒泡機(jī)制壕鹉,在父元素只綁定一次點(diǎn)擊事件:
var li = document.getElementsByTagName('li');
for(var i=0; i<li.length; i++){
li[i].setAttribute('i',i+1);
}
var ul = document.getElementById('wrapper');
ul.addEventListener('click', function(e){
if(e.target && e.target.nodeName.toUpperCase() === 'LI'){
var b = e.target.getAttribute('i');
console.log('這是第' + b + '個(gè)<li>元素');
}
});
見(jiàn) Demo剃幌。
這種事件委托的方式減少了事件處理程序晾浴,也能降低程序的復(fù)雜性和出錯(cuò)概率负乡。