jQuery綁定方法的區別 - .bind() / .live() / .delegate() / .on()

介紹

本文只對原文重點內容做出翻譯,幾乎涵蓋所有原文內容,如仍有疑惑請參考原文,地址在文章最下方給出。

[html] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. <ul id="members" data-role="listview" data-filter="true">  
  2.     <!-- ... more list items ... -->  
  3.     <li>  
  4.         <a href="detail.html?id=10">  
  5.             <h3>John Resig</h3>  
  6.             <p><strong>jQuery Core Lead</strong></p>  
  7.             <p>Boston, United States</p>  
  8.         </a>  
  9.     </li>  
  10.     <!-- ... more list items ... -->  
  11. </ul>  

bind方法

bind方法直接把事件類型與事件句柄註冊到所有滿足選擇器條件的DOM元素中。該方法經過長期的考驗,直接可靠,只是會有些性能問題。如下

[javascript] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. /* The .bind() method attaches the event handler directly to the DOM  
  2.    element in question ( "#members li a" ). The .click() method is  
  3.    just a shorthand way to write the .bind() method. */  
  4.    
  5. $( "#members li a" ).bind( "click"function( e ) {} );   
  6. $( "#members li a" ).click( function( e ) {} );   

上面兩種方式的效果一摸一樣,所有的鏈接都會獨立綁定到同一個事件控制句柄,比較浪費資源。

優勢 - 跨瀏覽器、方便快捷、支持快捷方法(.click()、.hover()等)、事件觸發時響應速度快。

劣勢 - 每個元素綁定同一個句柄副本(正確做法是綁定同一個句柄的引用)、無法應對動態加入的元素、元素多的時候會有性能問題、影響頁面加載速度。

live方法

live採用事件委託的概念,其調用方式與bind類似。它將事件句柄連同選擇器和事件信息一起綁定到document,這樣就可以讓事件句柄作用於所有事件。當事件冒泡至document時,jQuery則會查看選擇器和事件來決定是否調用句柄。這種方式會在用戶操作時多多少少有些影響性能,但初始註冊時卻很快。

[javascript] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. /* The .live() method attaches the event handler to the root level  
  2.    document along with the associated selector and event information  
  3.    ( "#members li a" & "click" ) */   
  4.    
  5. $( "#members li a" ).live( "click"function( e ) {} );  

上面的代碼與bind比起來,只需要把事件句柄綁定到document上就可以了,無需對所有滿足條件的DOM元素一一綁定。這樣做不僅效率高,而且節省資源,但這並不意味着這種方案毫無瑕疵。

優勢 - 與bind方式相比,只需要一個事件句柄實例;從bind升級到live改動很小,只需要替換方法名字即可;動態添加到DOM樹中,並滿足選擇器條件的元素也能按預期設想的那樣工作,因爲實際綁定的時候document元素,並非真實的目標DOM元素;句柄綁定可以在document的ready事件前完成,充分利用加載時間。

劣勢 - jQuery 1.7中已不推薦使用該方法;這個方法對鏈式操作控制的不好;選擇器中選出的元素基本上算是作廢了,因爲事件句柄是註冊到document的;event.stopPropagation()不再起作用,因爲document已經全權代理所有事件;因爲所有的選擇器和事件信息都是綁定到document的,所以在事件發生時jQuery會使用matchesSelector從大量的信息中找出匹配項來執行對應的事件句柄;事件會一直傳播到document,如何DOM層次很深的話會對性能產生影響。

delegate方法

delegate的實現思路與live類似,但並不要求必須綁定到document,開發人員可以自行決定綁定元素。

[javascript] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. /* The .delegate() method behaves in a similar fashion to the .live()  
  2.    method, but instead of attaching the event handler to the document,  
  3.    you can choose where it is anchored ( "#members" ). The selector  
  4.    and event information ( "li a" & "click" ) will be attached to the  
  5.    "#members" element. */  
  6.    
  7. $( "#members" ).delegate( "li a""click"function( e ) {} );  

delegate的功能非常很強悍。上面的代碼將事件句柄與事件信息一起註冊到無序列表("#members")。這要比live總是註冊到document的做法高效得多。另外delegate還解決了許多其它問題。

優勢 - 目標綁定元素可指定;選擇器不會預先執行,只是用來註冊到根元素;支持鏈式操作;jQuery仍舊便利註冊內容來查找匹配的選擇器和事件,只是數據量相比document來說已經大大減少;適用於動態添加的元素;如果綁定對象爲document,那麼綁定操作可以在document的ready事件前執行。

劣勢 - bind到delegate的過渡並不平滑,因爲畢竟方法簽名有出入;jQuery會使用matchesSelector並根據根元素中保存的選擇器和事件信息來判斷調用哪個句柄,其中的存儲信息數量不容小視,只是與live相比還算是小的。

on方法

我們所熟知的bind、live和delegate底層都是靠jQuery 1.7中的新方法on實現的;unbind、die和undelegate則是通過off實現的。具體細節請參見下面的代碼:

[javascript] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. // ... more code ...  
  2.    
  3. bind: function( types, data, fn ) {  
  4.     return this.on( types, null, data, fn );  
  5. },  
  6. unbind: function( types, fn ) {  
  7.     return this.off( types, null, fn );  
  8. },  
  9.    
  10. live: function( types, data, fn ) {  
  11.     jQuery( this.context ).on( types, this.selector, data, fn );  
  12.     return this;  
  13. },  
  14. die: function( types, fn ) {  
  15.     jQuery( this.context ).off( types, this.selector || "**", fn );  
  16.     return this;  
  17. },  
  18.    
  19. delegate: function( selector, types, data, fn ) {  
  20.     return this.on( types, selector, data, fn );  
  21. },  
  22. undelegate: function( selector, types, fn ) {  
  23.     return arguments.length == 1 ?   
  24.         this.off( selector, "**" ) :   
  25.         this.off( types, selector, fn );  
  26. },  
  27.    
  28. // ... more code ...  

on的使用方式如下:

[javascript] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. /* The jQuery .bind(), .live(), and .delegate() methods are just one  
  2.    line pass throughs to the new jQuery 1.7 .on() method */  
  3.    
  4. // Bind  
  5. $( "#members li a" ).on( "click"function( e ) {} );   
  6. $( "#members li a" ).bind( "click"function( e ) {} );   
  7.    
  8. // Live  
  9. $( document ).on( "click""#members li a"function( e ) {} );   
  10. $( "#members li a" ).live( "click"function( e ) {} );  
  11.    
  12. // Delegate  
  13. $( "#members" ).on( "click""li a"function( e ) {} );   
  14. $( "#members" ).delegate( "li a""click"function( e ) {} );  

on看起來像是一個擁有不同簽名、經過重載的方法。

優勢 - 爲各種事件綁定方法提供了一致的解決方案;簡化jQuery代碼,無需通過bind、live和delegate進行二次調用;在能夠保證擁有delegate方法所有優點的前提下,同時擁有bind方法所提供的好處。

劣勢 - 稍微有點混亂,其行爲取決於被調用的方式。

總結

如何在合適的場景使用合適的方法:

使用bind方法開銷比較大,因爲它會把同一個事件句柄附加到選擇器篩選出來的每一個元素。
不要使用live方法因爲官方已經把它定位爲deprecated,而且使用時還有許多問題。
delegate物超所值,既能滿足性能上的需求,又能自如應對動態添加的元素。
新的on方法算得上是一種語法糖,替代bind、live和delegate。
新方向是使用on方法。熟悉它的語法並開始嘗試在jQuery 1.7+項目中使用。

參考文檔:
http://www.elijahmanor.com/differences-between-jquery-bind-vs-live-vs-delegate-vs-on/
https://gist.github.com/elijahmanor/1749717

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章