介紹
本文只對原文重點內容做出翻譯,幾乎涵蓋所有原文內容,如仍有疑惑請參考原文,地址在文章最下方給出。
- <ul id="members" data-role="listview" data-filter="true">
- <!-- ... more list items ... -->
- <li>
- <a href="detail.html?id=10">
- <h3>John Resig</h3>
- <p><strong>jQuery Core Lead</strong></p>
- <p>Boston, United States</p>
- </a>
- </li>
- <!-- ... more list items ... -->
- </ul>
bind方法
bind方法直接把事件類型與事件句柄註冊到所有滿足選擇器條件的DOM元素中。該方法經過長期的考驗,直接可靠,只是會有些性能問題。如下
- /* The .bind() method attaches the event handler directly to the DOM
- element in question ( "#members li a" ). The .click() method is
- just a shorthand way to write the .bind() method. */
- $( "#members li a" ).bind( "click", function( e ) {} );
- $( "#members li a" ).click( function( e ) {} );
上面兩種方式的效果一摸一樣,所有的鏈接都會獨立綁定到同一個事件控制句柄,比較浪費資源。
優勢 - 跨瀏覽器、方便快捷、支持快捷方法(.click()、.hover()等)、事件觸發時響應速度快。
劣勢 - 每個元素綁定同一個句柄副本(正確做法是綁定同一個句柄的引用)、無法應對動態加入的元素、元素多的時候會有性能問題、影響頁面加載速度。
live方法
live採用事件委託的概念,其調用方式與bind類似。它將事件句柄連同選擇器和事件信息一起綁定到document,這樣就可以讓事件句柄作用於所有事件。當事件冒泡至document時,jQuery則會查看選擇器和事件來決定是否調用句柄。這種方式會在用戶操作時多多少少有些影響性能,但初始註冊時卻很快。
- /* The .live() method attaches the event handler to the root level
- document along with the associated selector and event information
- ( "#members li a" & "click" ) */
- $( "#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,開發人員可以自行決定綁定元素。
- /* The .delegate() method behaves in a similar fashion to the .live()
- method, but instead of attaching the event handler to the document,
- you can choose where it is anchored ( "#members" ). The selector
- and event information ( "li a" & "click" ) will be attached to the
- "#members" element. */
- $( "#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實現的。具體細節請參見下面的代碼:
- // ... more code ...
- bind: function( types, data, fn ) {
- return this.on( types, null, data, fn );
- },
- unbind: function( types, fn ) {
- return this.off( types, null, fn );
- },
- live: function( types, data, fn ) {
- jQuery( this.context ).on( types, this.selector, data, fn );
- return this;
- },
- die: function( types, fn ) {
- jQuery( this.context ).off( types, this.selector || "**", fn );
- return this;
- },
- delegate: function( selector, types, data, fn ) {
- return this.on( types, selector, data, fn );
- },
- undelegate: function( selector, types, fn ) {
- return arguments.length == 1 ?
- this.off( selector, "**" ) :
- this.off( types, selector, fn );
- },
- // ... more code ...
on的使用方式如下:
- /* The jQuery .bind(), .live(), and .delegate() methods are just one
- line pass throughs to the new jQuery 1.7 .on() method */
- // Bind
- $( "#members li a" ).on( "click", function( e ) {} );
- $( "#members li a" ).bind( "click", function( e ) {} );
- // Live
- $( document ).on( "click", "#members li a", function( e ) {} );
- $( "#members li a" ).live( "click", function( e ) {} );
- // Delegate
- $( "#members" ).on( "click", "li a", function( e ) {} );
- $( "#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