JS中的事件代理詳解

事件代理的定義

對(duì)于事件委托或者說(shuō)事件代理,有這樣一段定義:

事件委托就是利用事件冒泡,只指定一個(gè)事件處理程序,就可以管理某一類型的所有事件。

舉個(gè)例子來(lái)說(shuō)
首先我們創(chuàng)建一個(gè)擁有多個(gè)平行元素的列表

<ul id="parent-list">  
  <li id="post-1">Item 1</li>   
  <li id="post-2">Item 2</li>   
  <li id="post-3">Item 3</li>   
  <li id="post-4">Item 4</li>   
  <li id="post-5">Item 5</li>   
  <li id="post-6">Item 6</li> 
</ul>  

當(dāng)鼠標(biāo)移動(dòng)到li上或者點(diǎn)擊了li的時(shí)候,需要觸發(fā)相應(yīng)的事件,若果不使用事件代理,那么我們需要為每一個(gè)li都添加相應(yīng)的 onClick()或者 onMouseOver()事件,代碼如下:

function addListeners4Li(liNode) {
 liNode.onclick = function clickHandler(){alert('Click')};     
 liNode.onmouseover = function mouseOverHandler(){alert('MouseOver')} 
}

window.onload = function(){
  var ulNode = document.getElementById("parent-list"); 
  var liNodes = ulNode.getElementByTagName("Li"); //獲取所有l(wèi)i節(jié)點(diǎn)
  for(var i=0, l = liNodes.length; i < l; i++){    
    addListeners4Li(liNodes[i]); //為每一個(gè)li節(jié)點(diǎn)添加監(jiān)聽
 }

這種方法的缺點(diǎn)在于

  1. 由于在javascript中,每一個(gè)函數(shù)都是一個(gè)對(duì)象,是對(duì)象就會(huì)占用內(nèi)存,對(duì)象越多,占用的內(nèi)存也就越大,在上面的方法中,我們創(chuàng)建了6個(gè) liNodes對(duì)象,對(duì)每一個(gè)對(duì)象進(jìn)行監(jiān)聽,但是如果li的數(shù)量特別龐大時(shí),這種方法其實(shí)是很占用內(nèi)存的
  2. 在上面的方法中,我們對(duì)每一個(gè) liNodes對(duì)象都添加了監(jiān)聽,而在javascript中,添加到頁(yè)面中的事件處理程序數(shù)量將直接影響程頁(yè)面的整體性能,因?yàn)槭录幚沓绦蛟蕉?,與dom交互的次數(shù)就越多,引起瀏覽器重繪與重排的次數(shù)也就越多,從而拖慢頁(yè)面的就緒時(shí)間。
  3. 如果我們需要頻繁的刪除和添加 li元素,就需要在每一次添加時(shí)都為其綁定事件,過(guò)于繁瑣。

總結(jié)一下就是:

**1. 創(chuàng)建的js對(duì)象過(guò)多,占用內(nèi)存

  1. JS與DOM之間的關(guān)聯(lián)過(guò)多,影響性能,容易造成內(nèi)存泄漏
  2. 需要管理的函數(shù)過(guò)多,對(duì)于每個(gè)元素都要添加監(jiān)聽**

使用事件代理可以很好的解決這兩個(gè)問(wèn)題,但在我們介紹事件代理之前,先要說(shuō)一下事件的冒泡機(jī)制


事件的冒泡及捕獲

不同的瀏覽器對(duì)于事件的冒泡及捕獲有不同的處理方式,這里主要介紹W3C對(duì)DOM2.0定義的標(biāo)準(zhǔn)事件:

圖片.png

事件捕獲:當(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è)過(guò)程中,事件相應(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)來(lái)組織事件的冒泡傳播。

其中 addEventListener(eventType,callBack,true | false)函數(shù)的第三個(gè)屬性為 useCapture這個(gè)屬性默認(rèn)為 false意為在事件冒泡階段調(diào)用事件處理函數(shù),如果為 true則是在事件捕獲階段調(diào)用事件處理函數(shù)。


事件代理的使用

對(duì)于上面的代碼,我們可以使用事件代理來(lái)進(jìn)行簡(jiǎn)化,只對(duì)平行元素共同的父元素進(jìn)行監(jiān)聽,根據(jù)其獲取的源事件屬性,來(lái)做出相應(yīng)的處理:

document.getElementById("parent-list").addEventListener("click",function(e) { 
  //檢查事件源的屬性
  if(e.target && e.target.nodeName.toUpperCase == "LI") { 
    console.log("List item ",e.target.id.replace("post-")," was clicked!"); 
  }
}

在上述代碼中,在 click()事件的毀掉函數(shù)中有一個(gè)源事件 e,通過(guò)查看源事件中的屬性,我們可以確定當(dāng)前事件是從哪個(gè)元素觸發(fā)的,從而做出相應(yīng)的Actions

參考:
淺析JavaScript的事件代理和委托
js中的事件委托或是事件代理詳解

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • ??JavaScript 與 HTML 之間的交互是通過(guò)事件實(shí)現(xiàn)的。 ??事件,就是文檔或?yàn)g覽器窗口中發(fā)生的一些特...
    霜天曉閱讀 3,716評(píng)論 1 11
  • 1.背景介紹 1.1什么是事件委托? 事件委托還有一個(gè)名字叫事件代理,JavaScript高級(jí)程序設(shè)計(jì)上講:事件委...
    我叫于搞吧閱讀 1,718評(píng)論 4 9
  • js之事件機(jī)制 1、事件初探 1.1 js事件的概述 JavaScript事件:JavaScript是基于事件驅(qū)動(dòng)...
    道無(wú)虛閱讀 2,639評(píng)論 0 2
  • (續(xù)jQuery基礎(chǔ)(1)) 第5章 DOM節(jié)點(diǎn)的復(fù)制與替換 (1)DOM拷貝clone() 克隆節(jié)點(diǎn)是DOM的常...
    凜0_0閱讀 1,531評(píng)論 0 8
  • 第一部分 HTML&CSS整理答案 1. 什么是HTML5? 答:HTML5是最新的HTML標(biāo)準(zhǔn)。 注意:講述HT...
    kismetajun閱讀 28,887評(píng)論 1 45

友情鏈接更多精彩內(nèi)容