事件委托,說白了就是本來你要給一個元素添加一個事件(比如點選),出于某些考率,現在要把事件添加給它的外層元素。
事件源
解釋事件委托之前,應該先了解下事件源。簡單來說,事件源就是直接觸發事件的元素。在事件函數中可通過event對象的target屬性通路事件源。
看一個例子:
圖中,單擊span部分,控制台會列印出對應span元素;單擊span外的p部分,會列印出對應p元素;單擊p外的div部分,會列印出對應div元素。

關鍵代碼如下:
1 <body>
2 <div id="box">div
3 <p>p
4 <span>span</span>
5 </p>
6 </div>
7 </body>
8 <script>
9 window.onload=function(){
10 var box=document.getElementById("box");
11 box.onclick=function(ev){
12 console.log((ev || window.event).target);
13 };
14 </script>
事件委托
再說事件委托。通常,我們用事件委托解決兩問題:1、避免不必要的性能開銷;2 、新生成的元素不需要重新添加事件。
先看一個經典的例子:
例子中,我們希望點選li能列印對應的文本。
1 <body>
2 <ul id="list">
3 <li>red</li>
4 <li>green</li>
5 <li>blue</li>
6 <li>pink</li>
7 <li>black</li>
8 </ul>
9 </body>
10 <script>
11 var list=document.getElementById("list");
12 var lis=document.querySelectorAll("li");
13
14 for(var i=0;i<lis.length;i++){
15 lis[i].onclick=function(){
16 console.log(this.firstChild.nodeValue); //本來單擊li,可以列印出其對應文本
17 };
18 }
19
20 list.innerHTML+='<li>yellow</li>'; //這裡加了一行後,單擊li就無法列印出li對應文本了
21 </script>
本來,單擊li是可以在控制台列印對應文體的。但是,現在20行加了一行代碼,單擊li就無法列印出li對應文本了。因為innerHTML會将原有内容全部清空,再賦予新内容,是以li綁定的單擊事件也将失效。類似這種情況的還有,使用cloneNode(),新節點不會複制源節點的事件;jQuery中通過remove()移除的節點,重新添加回來後,之前綁定的事件将失效。(PS:detach()在這點上與remove()不同。)
下面,我将上面代碼中的for循環換成以下代碼:
1 list.onclick = function(ev){
2 var ev = ev || window.event;
3 if(ev.target.tagName.toLowerCase()=='li'){
4 console.log(ev.target.innerHTML); //單擊li,即事件源是li是列印出其對應文本
5 }
6 };
這樣就解決了剛才遇到的問題,而且避免了使用for循環。其實,在這個解決方案中,我們是把點選事件綁定在了li的父級元素ul身上,也就是所謂的事件委托。然後對事件源進行判斷,等于間接地給li添加了點選事件。
本作品采用知識共享署名 4.0 國際許可協定進行許可。