在javasript
中delegate
這個(gè)詞經(jīng)常出現(xiàn),看字面的意思,代理、委托。
要搞懂事件代理,我們先來看看什么是代理,相信我們生活中現(xiàn)在還有朋友在做微商的,而微商的產(chǎn)品就是一級(jí)一級(jí)代理,下家找上家拿貨這樣子,你賣了東西從上家拿貨,這個(gè)過程相當(dāng)于你也有了貨
我們?cè)趺磸淖置嫔蟻砹私馐录拇砟?慢慢來,我們先來看一個(gè)需求,有這樣一個(gè)列表,當(dāng)我們每次點(diǎn)擊的時(shí)候,就在控制臺(tái)打印列表里的內(nèi)容
作為一名新手,我經(jīng)常這樣綁定onclick
事件
我會(huì)循環(huán)每一個(gè)li
當(dāng)我點(diǎn)擊一個(gè)在控制臺(tái)顯示打印結(jié)果,全部綁定click
事件,于是,我的代碼是這樣的
<ul class="ct">
<li>我是一號(hào)</li>
<li>我是二號(hào)</li>
<li>我是三號(hào)</li>
<li>我是四號(hào)</li>
<li>我是五號(hào)</li>
</ul>
<button type = "button" id="btn">增加</button>
var ul = document.querySelector(".ct")
for(var i=0;i<ul.children.length;i++){
ul.children[i].onclick = function(){
console.log(this.innerText)
}
}
我覺得這樣寫的挺好的,可是有人說這樣會(huì)耗費(fèi)性能,那我就不管了,可是當(dāng)我改了一下需求,我發(fā)現(xiàn)這個(gè)代碼用的沒那么舒服了
我在代碼中通過js加入新的li,當(dāng)我點(diǎn)擊新的li時(shí),控制臺(tái)沒有打印我的代碼?怎么回事?
我加入了幾這樣的代碼
var btn =document.querySelector("#btn")
var i =6
btn.addEventListener("click",function(){
var node = document.createElement("li")
node.innerText = "我是" + i++ + "號(hào)"
ul.appendChild(node)
})
這是為什么?因?yàn)樵械膌i跟我后面生成的li根本不是同時(shí)發(fā)生的,在創(chuàng)建新的li元素之前,已經(jīng)給存在的li加事件了,好吧,那我怎么修改呢?難道要重新循環(huán)遍歷,太麻煩了,
有人告訴我可以用代理,代理是什么,看了文章,好吧,修改一下代碼
ul.addEventListener("click",function(e){
// 檢查事件源e.targe是否為L(zhǎng)i
if(e.target.nodeName.toLowerCase() == 'li'){
console.log(e.target.innerText)
}
})
新增新的點(diǎn)擊
li
也會(huì)再控制臺(tái)打印,解決了,于是耐心翻資料看了一下什么是事件代理:
定義:事件委托就是利用事件冒泡,只指定一個(gè)事件處理程序,就可以管理某一類型的所有事件。
那什么是冒泡呢?
- 當(dāng)一個(gè)元素上的事件被觸發(fā)的時(shí)候,比如說鼠標(biāo)點(diǎn)擊了一個(gè)按鈕,同樣的事件將會(huì)在那個(gè)元素的所有祖先元素中被觸發(fā)。這一過程被稱為事件冒泡
回到我們本文的這個(gè)例子,看看改動(dòng)后的代碼,我把onlick事件綁定到了ul標(biāo)簽上面,而不是li標(biāo)簽。
于是,當(dāng)我點(diǎn)擊任何一個(gè)li標(biāo)簽
(不管是動(dòng)態(tài)生成的還是之前就有的)是,這個(gè)事件就開始冒泡,尋找父元素。由于我這里給ul綁定了onlick,那么這時(shí),ul會(huì)捕獲冒泡上來的onclick事件。
接著,如果,這個(gè)target剛剛好就是li標(biāo)if(target.nodeName.toLowerCase() == 'li')
,那么執(zhí)行函數(shù)。
簡(jiǎn)單介紹一下事件傳播機(jī)制,主要介紹DOM2.0
- DOM2.0模型將事件處理流程分為三個(gè)階段:一、事件捕獲階段,二、事件目標(biāo)階段,三、事件起泡階段。如圖:
事件捕獲:當(dāng)某個(gè)元素觸發(fā)某個(gè)事件(如onclick),頂層對(duì)象document就會(huì)發(fā)出一個(gè)事件流,隨著DOM樹的節(jié)點(diǎn)向目標(biāo)元素節(jié)點(diǎn)流去,直到到達(dá)事件真正發(fā)生的目標(biāo)元素。在這個(gè)過程中,事件相應(yīng)的監(jiān)聽函數(shù)是不會(huì)被觸發(fā)的。
事件目標(biāo):當(dāng)?shù)竭_(dá)目標(biāo)元素之后,執(zhí)行目標(biāo)元素該事件相應(yīng)的處理函數(shù)。如果沒有綁定監(jiān)聽函數(shù),那就不執(zhí)行。
事件起泡:從目標(biāo)元素開始,往頂層元素傳播。途中如果有節(jié)點(diǎn)綁定了相應(yīng)的事件處理函數(shù),這些函數(shù)都會(huì)被一次觸發(fā)。如果想阻止事件起泡,可以使用e.stopPropagation()(Firefox)或者e.cancelBubble=true(IE)來組織事件的冒泡傳播。