概念:
- JavaScript高級(jí)程序設(shè)計(jì) (簡稱JS高程) :事件代理 (事件委托) 利用了事件冒泡,只指定一個(gè)事件處理程序,就可以管理某一類型的所有事件。
作用:
-
減少與dom的交互次數(shù),提高代碼性能。 (--代碼性能--)
- 在JavaScript中,添加到頁面上的事件處理程序數(shù)量將直接關(guān)系到頁面的整體運(yùn)行性能,因?yàn)樾枰粩嗟呐cdom節(jié)點(diǎn)進(jìn)行交互,訪問dom的次數(shù)越多,引起瀏覽器重繪與重排的次數(shù)也就越多,就會(huì)延長整個(gè)頁面的交互就緒時(shí)間,這就是為什么性能優(yōu)化的主要思想之一就是要減少DOM操作;如果使用事件代理,就會(huì)將所有的操作放到j(luò)s程序里面,與dom的操作就只需要交互一次,這樣就能大大的減少與dom的交互次數(shù),提高性能。
- JS高程上關(guān)于代碼優(yōu)化中提到了:如果可能,在文檔級(jí)別附加事件處理程序,這樣可以處理整個(gè)頁面的事件。
-
動(dòng)態(tài)生成DOM元素時(shí),可通過事件代理給新增的元素添加事件函數(shù)。
- 比如在異步獲取后臺(tái)數(shù)據(jù)加載頁面時(shí),直接給動(dòng)態(tài)生成的DOM元素綁定事件函數(shù)可能需要在ajax交互時(shí)加入事件函數(shù),這樣往往會(huì)使得代碼變得混亂,而使用事件代理則會(huì)非常方便。
原理:
- 事件冒泡:事件開始時(shí)由嵌套層次最深的節(jié)點(diǎn)開始接收,然后逐級(jí)向其父級(jí)節(jié)點(diǎn)傳播。
- 例:頁面中有 div>ul>li>p 的結(jié)構(gòu),當(dāng)你 click 了 p 元素,click 事件首先在 p 元素上發(fā)生,然后,click 事件沿DOM樹向上傳播,分別在 li>ul>div 上發(fā)生,按照J(rèn)S高程上的說明,最終會(huì)傳播到 document 對(duì)象。
- 注:與事件冒泡對(duì)應(yīng)的還有事件捕獲。
- 事件代理:利用事件冒泡原理,把事件函數(shù)綁定在父級(jí)元素上,再指定需要執(zhí)行函數(shù)的子元素執(zhí)行事件函數(shù);在觸發(fā)事件時(shí),事件會(huì)依次冒泡到父級(jí)元素,從而觸發(fā)綁定在父級(jí)元素的事件函數(shù)。
- 對(duì)于事件代理原理的理解,閱讀下面關(guān)于事件對(duì)象和具體用法的介紹后會(huì)更加清晰。
用法:
1.原生JS
-
事件對(duì)象:在觸發(fā)DOM上的某個(gè)事件時(shí),會(huì)產(chǎn)生一個(gè)事件對(duì)象 event,這個(gè)對(duì)象中包含著所有與事件有關(guān)的信息,在執(zhí)行事件處理程序時(shí) event 對(duì)象會(huì)被傳入;只有在事件處理程序執(zhí)行期間,event 對(duì)象才會(huì)存在;一旦事件處理程序執(zhí)行完成,event 對(duì)象就會(huì)被銷毀;對(duì)于事件代理,這里重點(diǎn)介紹下 event 的幾個(gè)屬性。
- currentTarget :其事件函數(shù)當(dāng)前正在處理事件的那個(gè)元素;如果感覺這個(gè)定義有點(diǎn)拗口,你可以暫且把 currentTarget 簡單的理解為原生JS中事件函數(shù)內(nèi)部的 this 。
- target :事件目標(biāo);即觸發(fā)事件的實(shí)際目標(biāo)。
- 這里用一個(gè)例子說明:假設(shè)頁面中有 ul>li>p 的結(jié)構(gòu),然后點(diǎn)擊 p 標(biāo)簽來執(zhí)行下面代碼(這里為方便閱讀沒有做兼容性處理,此代碼需要在chrome瀏覽器下運(yùn)行)
var ul = document.querySelector('ul'); var li = document.querySelector('li'); var p = document.querySelector('p'); ul.onclick = function(event) { console.log(this); // <ul>...</ul> console.log(event.currentTarget); // <ul>...</ul> console.log(event.target); // <p>...</p> }
從運(yùn)行結(jié)果可以看到,當(dāng)把事件函數(shù)綁定在父元素時(shí),currentTarget 屬性和函數(shù)內(nèi)部的 this 都為綁定事件函數(shù)的父元素,而 target 屬性的值則是我們想要觸發(fā)事件的子元素。
具體用法:給父元素綁定事件函數(shù),然后通過條件判斷找到需要執(zhí)行事件函數(shù)的元素。
頁面結(jié)構(gòu)如下:
<ul>
<li><p id="aaa">AAA</p></li>
<li><p id="bbb">BBB</p></li>
</ul>
JS代碼如下:
var ul = document.querySelector('ul');
var li = document.querySelector('li');
var p = document.querySelector('p');
ul.onclick = function(e) {
// 兼容性處理
var e = e || window.event;
var target = e.target || e.srcElement;
switch (target.id){
case "aaa":
alert("AAA");
break;
case "bbb":
alert("BBB");
break;
default :
alert("未點(diǎn)擊 p 標(biāo)簽");
break;
}
}
從測(cè)試結(jié)果可以看到,只在父元素上綁定一次事件函數(shù),通過條件判斷可以分別找到父元素下觸發(fā)事件的子元素,然后分別進(jìn)行操作。
2.jQuery
- jQuery 的 on 方法中已經(jīng)封裝好了事件代理的功能,而且事件函數(shù)內(nèi)部的 this 直接指向的就是被指定的元素。
// on 的3個(gè)參數(shù) 1.事件類型 2.給事件指定的元素 3.事件函數(shù)
$("div").on("click", "p", function () {
alert("p");
console.log(this); // p
})
注意 jQuery 的 on 方法中 this 直接指向的就是觸發(fā)事件的子元素 p 。
結(jié)尾:
- 原生JS中的一些事件如 onmouseover 存在一些不好用的問題,同時(shí)通過 target 等屬性進(jìn)行篩選又需要寫不少條件判斷的代碼,相比下jQuery 的 on 方法則封裝得簡單直接,但是這里并非單純推薦使用第三方庫,實(shí)際應(yīng)用中要根據(jù)具體需求做選擇。
會(huì)同步在 kabumie 的 github 空間上