jquery live() delegate() on() 事件委託的一些區別

隨着DOM結構的複雜化和Ajax等動態腳本技術的運用,有了較多的動態添加進來的元素,直接用JQ添加click事件會發現新添加進來的元素並不能直接選取到,在這裏就須要用到事件委託方法,JQ爲事件委託提供了live()、dalegate()和on()方法。   jquery

事件委託

咱們知道,DOM在爲頁面中的每一個元素分派事件時,相應的元素通常都在事件冒泡階段處理事件。在相似 body > div > a 這樣的結構中,若是單擊a元素,click事件會從a一直冒泡到div和body(即document對象)。所以,發生在a上面的單擊事件,div和body元素一樣能夠處理。而利用事件傳播(這裏是冒泡)這個機制,就能夠實現事件委託。具體來講,事件委託就是事件目標自身不處理事件,而是把處理任務委託給其父元素或者祖先元素,甚至根元素(document)。數組

.live()閉包

jQuery 1.3新增的live()方法,用法以下:函數

$("#info_table td").live("click",function(){/*顯示更多信息*/});

這裏的.live()方法會把click事件綁定到$(document)對象,並且只須要給$(document)綁定一次,而後就可以處理後續動態加載的單元格的單擊事件。在接收到任何事件時,$(document)對象都會檢查事件類型和事件目標,若是是click事件且事件目標是td,那麼就執行委託給它的處理程序。性能

到目前爲止,一切彷佛很完美。惋惜,事實並不是如此。由於.live()方法並不完美,它有以下幾個主要缺點:spa

  • $()函數會找到當前頁面中的全部td元素並建立jQuery對象,但在確認事件目標時卻不用這個td元素集合,而是使用選擇符表達式與event.target或其祖先元素進行比較,於是生成這個jQuery對象會形成沒必要要的開銷;code

  • 默認把事件綁定到$(document)元素,若是DOM嵌套結構很深,事件冒泡經過大量祖先元素會致使性能損失;orm

  • 只能放在直接選擇的元素後面,不能在連綴的DOM遍歷方法後面使用,即$("#infotable td").live...能夠,但$("#infotable").find("td").live...不行;對象

  • 收集td元素並建立jQuery對象,但實際操做的倒是$(document)對象,使人費解。blog

解決之道

爲了不生成沒必要要的jQuery對象,可使用一種叫作「早委託」的hack,即在$(document).ready()方法外部調用.live():

(function($){
    $("#info_table td").live("click",function(){/*顯示更多信息*/});
})(jQuery);

在此,(function($){...})(jQuery)是一個「當即執行的匿名函數」,構成了一個閉包,能夠防止命名衝突。在匿名函數內部,$參數引用jQuery對象。這個匿名函數不會等到DOM就緒就會執行。注意,使用這個hack時,腳本必須是在頁面的head元素中連接和(或)執行的。之因此選擇這個時機,由於這時候恰好document元素可用,而整個DOM還遠未生成;若是把腳本放在結束的body標籤前面,就沒有意義了,由於那時候DOM已經徹底可用了。

爲了不事件冒泡形成的性能損失,jQuery從1.4開始支持在使用.live()方法時配合使用一個上下文參數:

$("td",$("#info_table")[0]).live("click",function(){/*顯示更多信息*/});

這樣,「受託方」就從默認的$(document)變成了$("#infotable")[0],節省了冒泡的旅程。不過,與.live()共同使用的上下文參數必須是一個單獨的DOM元素,因此這裏指定上下文對象時使用的是$("#infotable")[0],即便用數組的索引操做符來取得的一個DOM元素。

.delegate()

如前所述,爲了突破單一.bind()方法的侷限性,實現事件委託,jQuery 1.3引入了.live()方法。後來,爲解決「事件傳播鏈」過長的問題,jQuery 1.4又支持爲.live()方法指定上下文對象。而爲了解決無謂生成元素集合的問題,jQuery 1.4.2乾脆直接引入了一個新方法.delegate()。

使用.delegate(),前面的例子能夠這樣寫:

$("#info_table").delegate("td","click",function(){/*顯示更多信息*/});

使用.delegate()有以下優勢(或者說解決了.live()方法的以下問題):

  • 直接將目標元素選擇符("td")、事件("click")及處理程序與「受拖方」$("#info_table")綁定,不額外收集元素、事件傳播路徑縮短、語義明確;

  • 支持在連綴的DOM遍歷方法後面調用,即支持$("table").find("#info").delegate...,支持精確控制;

可見,.delegate()方法是一個相對完美的解決方案。但在DOM結構簡單的狀況下,也可使用.live()。

提示:使用事件委託時,若是註冊到目標元素上的其餘事件處理程序使用.stopPropagation()阻止了事件傳播,那麼事件委託就會失效。

 在下列狀況下,應該使用.live()或.delegate(),而不能使用.bind():

  • 爲DOM中的不少元素綁定相同事件;

  • 爲DOM中尚不存在的元素綁定事件;

 .on()

根據jQuery 1.7 Beta 1的發版說明,jQuery 1.7爲了解決.bind()、.live()和.delegate()並存形成的不一致性問題,將會增長一對新的事件方法:.on()和.off(),如下爲on()的實現方式:

.on( events [, selector ] [, data ], handler(eventObject) )

一個簡單的事件綁定如 $('button').on('click',function(){}); 與bind()無二樣。
在須要爲較多的元素綁定事件的時候,優先考慮事件委託,能夠帶來性能上的好處。好比:
 

 

如上圖,將click事件綁定在document對象上,頁面上任何元素髮生的click事件都冒泡到document對象上獲得處理。

注意到.on()的描述中第二個可選參數:selector。以下圖,添加了第二個參數,選擇符button:

 結果:

當事件冒泡到document對象時,檢測事件的target,若是與傳入的選擇符(這裏是button)匹配,就觸發事件,不然不觸發。 

注意.on()也能夠接收一個對象參數,該對象的屬性是事件類型,屬性值爲事件處理函數。下面是官方文檔的一個例子:

 

最後有一點,原先的live()方法,處理函數是默認綁定在document對象上不能變的,若是DOM嵌套結構很深,事件冒泡經過大量祖先元素會致使較大的性能損失。而使用.on()方法,事件只會綁定到$()函數的選擇符表達式匹配的元素上(上面個人例子中,爲了簡單綁定到了document),所以能夠精確地定位到頁面中的一部分,而事件冒泡的開銷也能夠減小。delegate()與on()同理,畢竟是用on()實現的:

 .on()和.off():實現方式
$(elems).on(events, selector, data, fn);
$(elems).off(events, selector, fn);
若是指定selector,則爲事件委託;不然,就是常規綁定。新舊API對應以下:

相關文章
相關標籤/搜索