JS和JQuery中的事件委託 學習筆記
事件委託其實並不是一個很進階的技巧,比如在一個頁面裡面,當只存在兩個按鈕的時候,可能你給按鈕添加監聽是這樣的:(本文不考慮瀏覽器安全色性,關於事件的相容性可參考前面的學習筆記)
按鈕1按鈕2
var btn1 = document.getElementById(btn1);var btn2 = document.getElementById(btn2);btn1.addEventListener(click, clickHandler1);btn2.addEventListener(click, clickHandler2);
當按鈕越來越多的時候,甚至到了幾十上百的時候,我相信很少有人會選擇一個一個的添加事件,首先,其實事件處理函數每個都是對象,都會佔用記憶體,建立的越多,記憶體開銷越大,效能越差;其次,大量“重複”性的代碼擁擠在指令碼裡,非常難以維護,也非常難看;還有,添加大量監聽意味著要頻繁訪問DOM元素,延遲整個頁面的訪問時間。
事件委託就是解決這個問題的一個方案。我們知道,在DOM節點構成的DOM樹中,子節點產生一個事件之後會逐級冒泡到父元素上:
事件委託就利用這一特性,只需給所有的按鈕的父元素比如container添加一個事件,這樣無論是哪個按鈕,只要觸發了綁定的事件都會冒泡到container上,我們只需判斷是不是你想監聽的按鈕即可。
var container = document.getElementById(container);container.addEventListener(click, function(e){ //擷取事件觸發對象 var target = e.target; if(target.id == btn1){ alert(btn1); }else if(target.id == btn2){ alert(btn2); }});
這個方法還有一個明顯的好處是你不必再問以後建立的元素添加監聽。比如在上面的判斷裡添加
else if(target.id == btn3){ alert(btn3);}
添加這個事件處理常式的時候頁面中還並沒有btn3,但btn3很可能是由使用者動態建立的,但不管使用者什麼時候建立,你都能在這個條件裡捕獲它。
JQuery裡面的事件委託
其實在JQuery裡,因為很容易建立一個JQuery集合,所以處理事件相對簡單。
一、click函數、bind函數等:
$(a).click(function(){ if($(this).hasClass(a1)){ //... }else if(...){ //... }});$(a).bind(click, function(){ if($(this).hasClass(a1)){ //... }else if(...){ //... }});
其實這個方法同樣也是通過遍曆所有a標籤,給他們添加事件函數,但比原生js代碼量要少很多。
二、live()
live和上面講的原生js類似,不指定父元素的時候,將事件綁定在了document上,比如:
$(.link).live(click, function(){ //...});
當有事件冒泡到document上時,將檢查事件是否為click事件,元素是否帶有link的className,滿足這兩個條件則將觸發事件處理函數。
除了預設綁定在document上,也可以綁定在指定父元素上:
$(.link, $(#container)).live(click, function(){ //...});
三、delegate
其實不管是live還是bind,他們的寫法都很奇怪,我們討論的事件委託都是給父元素添加的事件監聽,但一直到現在都好像是在子項目上調用的方法,不過還好JQuery裡面還有一個函數:delegate。
同樣是綁定事件到.link篩選條件上,使用delegate方法如下:
$(#container).delegate(.link, click, function(){ //...});
可以看到,我們在需要綁定的父元素(id名為container的元素)上調用的delegate方法,並傳遞三個參數:監聽元素篩選條件、監聽事件名、事件處理函數。
通過鏈式調用更加舒服:
$(#container).delegate(.link, click, function(){ //...}).delegate(.btn, click, function(){ //...}).delegate(.whatever, click, function(){ //...});
注意
bind是不能為後面動態產生的元素繫結事件的(因為調用bind時遍曆的是當時頁面裡的所有元素)。
live和delegate是可以為動態產生的元素觸發事件處理函數的,因為綁定在父元素上的只是一個篩選條件。
最後需要注意的是同樣是綁定在document元素上的click事件:
$(.btn).live(click, function(){ //...});$(document).delegate(.btn, click, function(){ //...});
最好使用delegate方法,因為雖然live同樣是綁定在document上,但$(“.btn”)這句代碼還是會遍曆所有的.btn元素並給其建立JQuery對象,相比於直接使用document,效能上會有所不如。
當然,就拿寫法來說,我們也更應該喜歡delegate方法。