JavaScript與HTML之間的交互是通過事件實現(xiàn)的痕鳍。在學(xué)習(xí)事件委托之前,我們需要先了解事件綁定望拖、事件監(jiān)聽、事件派發(fā)挫鸽。
事件綁定
要使JS對用戶操作做出響應(yīng)说敏,第一步就需要給DOM元素綁定相應(yīng)的事件函數(shù)。事件綁定有三種方法:
<ul id='list' onclik='event()'>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
1.直接在DOM元素上綁定
function event(){
console.log('給ul綁定成功')
}
2.DOM level 0:在JS代碼里添加
var ul = document.getElementById('list')
ul.onclick = function (){
console.log('給ul綁定成功')
}
3.DOM level 2:添加事件委托
前兩種方法在一個元素有多個事件需要執(zhí)行的時候只執(zhí)行最后綁定的事件丢郊,既最后一個事件會覆蓋前面的事件盔沫。另外医咨,這需要給每一個li
寫一個監(jiān)聽器,這樣既麻煩又占內(nèi)存架诞。所以我們我們推薦使用第三種方法拟淮。
事件監(jiān)聽
事件監(jiān)聽可以解決事件覆蓋的問題,我們用addEventListener()來實現(xiàn)監(jiān)聽事件
//添加事件函數(shù)
function event1(){
console.log('給ul綁定成功1')
}
function event2(){
console.log('給ul綁定成功2')
}
//給相應(yīng)的事件添加監(jiān)聽器
var ul =document.querySelector('#list')
ul.addEventListener('click',event1)
ul.addEventListener("mouseover", event2);
事件監(jiān)聽還有一個優(yōu)點是它可以控制listener 的觸發(fā)階段侈贷。(即可以選擇捕獲或者冒泡)惩歉。接下來我們了解一下什么是捕獲階段和冒泡階段
事件派發(fā)
DOM內(nèi)的事件傳播(或事件派發(fā))總是沿著其文檔節(jié)點和其附元素所構(gòu)成的有序列表進行的。
-
捕獲階段(Event capturing)
事件捕獲的思想是不太具體的節(jié)點應(yīng)該更早接收到事件俏蛮,而具體的節(jié)點應(yīng)該最后接收到事件撑蚌。事件捕獲的用意在于在事件到達預(yù)定目標(biāo)之前捕獲它。
簡單一點解釋事件捕獲就是當(dāng)事件觸發(fā)時先通知parent搏屑,再通知child 争涌。
-
冒泡階段(Event Bubbling)
事件開始時由最具體的元素(文檔嵌套層次最深的那個節(jié)點)接收,然后逐級向上傳播到較為不具體的節(jié)點(文檔)辣恋。
簡單一點解釋事件冒泡就是當(dāng)事件觸發(fā)時先通知child亮垫,再通知parent。
下圖展現(xiàn)了兩種事件通知順序:
注:我們可以使用
stopPropagation()
來阻止冒泡事件
另外上一節(jié)提到的addEventListener()
可以控制事件順序的優(yōu)點伟骨,既在addEventListener()
里添加一個參數(shù)false
(執(zhí)行冒泡)或者true
(執(zhí)行捕獲)饮潦,addEventListener()
默認(rèn)為false
事件委托
事件委托基于以上三個知識點,下面我們來舉一個例子
<ul id="list">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
var list = document.querySelector('#list')
list.addEventListener('click',function (e){
if(e.target.tagName === 'LI'){
console.log('當(dāng)前元素事件觸發(fā)成功')
}
})
這是常規(guī)的實現(xiàn)事件委托的方法携狭,但是這種方法有BUG继蜡,當(dāng)監(jiān)聽的元素里存在子元素時,那么我們點擊這個子元素事件會失效逛腿,所以我們可以聯(lián)系文章上一小節(jié)說到的冒泡事件傳播機制來解決這個bug稀并。改進的事件委托代碼:
var ul = document.querySelector('#list')
list.addEventListener('click',function (e){
var l = e.target
//從target(點擊)元素向上找currentTarget(監(jiān)聽)元素,找到了想委托的元素就觸發(fā)事件单默,沒找到就返回null
while(l.tagName !== 'LI'){
l = l.parentNode
if(l === ul){
l = null
break;
}
}
if (l) {
console.log('你點擊了ul里的li')
}
})
事件委托的優(yōu)點:
- 減少監(jiān)聽器
- 監(jiān)聽動態(tài)內(nèi)容
上面寫的事件委托的代碼可以解決大部分事件碘举,但是不一定百分之百沒問題,還是要具體事件具體分析搁廓。