[jQuery note.] jQuery 1.5 在 Events 的探勘

UPDATE, 還是認真說明一下好了(笑)

委派事件(delegate)跟 live 事件其實是指同一件事情,不過有幾個地方不同:

  1. 由於 live 事件直接綁定在 document 上,所以一旦有中途有事件傳播被取消(stopPropagation),該 live 事件就不會被觸發。
  • 委派事件(delegate)同樣使用 live 事件的綁定方式,不同的是,他的事件傳播會依序傳回直到被中斷為止。

請看以下範例:

差異性在:

  • 完全不中斷,所有事件都執行完畢。
  • 從父元件(DIV#workspace)中斷,使用委派事件的子元件依舊會執行,使用 live 則被中斷
  • 從 body(DOM#Element)中斷,二者皆執行到 body 事件後中斷,live 依舊不執行
  • 從 live 本身中斷,無效!並無法中斷該事件傳播!

這就是委派事件與 live 事件的差異性。在使用 live 的時候,得注意事件傳播是否有被中斷,否則一旦使用了 stopPropagation(),則有可能會讓 .live 事件消失。

以下是舊文

首先我要說的是,在 jQuery 1.5 有改寫 Events 的部份,所以測試的環節不能拿 1.4+ 的來用,會出錯。至於為什麼會這樣?這不要問我,還是去問官方會比較實際。反正,改都改了,除非你有拿 jQuery 的核心來做一些 齷齪的事情,不然應該不會有影響才是。像是我之前寫的筆記,就只能用在 1.4+ 以前的版本,拿到 1.5 來用可能就會出問題了。

首先是,Events 綁定之後,在 $.cache 中會多一層物件(Object),命名方式是以 jQuery 尾數加上一串亂數而成。跟 1.4+ 相比,要取得 $.cache 的內容就變得相對複雜許多。當然,要取得 jQuery 的亂數,還是有一些暗黑技法可以用,反正多看幾次原始碼,要找到寶藏其實也沒那麼困難。

// jqExpando 應該是 jQuery15028725506574846804 這種樣子。
var jqExpando = jQuery.expando;

這樣就可以了!請不要懷疑,這個參數是由 jQuery 自身去 extend 的,所以確實是可以取出。至於這個變數會不會被改變?會!當你的頁面重新讀取 jQuery 的時候,他是會改變的。

然後來簡單筆記 delegatelive 的差異性。其實,端看原始碼,這兩種東西幾乎是一樣的,你在原始碼中也會發現,其實呼叫 delegate,他會去呼叫 live 來用。那我就直接用 live 就好啦!事實上,事情當然不像我這種阿呆想得那麼簡單!根據官方的說法是:

Attach a handler to one or more events for all elements that match the selector, now or in the future, based on a specific set of root elements.

由於我英文不好,所以我就一言以蔽之:有老爸罩比較好辦事(喂喂喂)!

另外一點,官方有特別提起在 livedelegate 之中,關於 event.stopPropagation() 的不同。根據官方的說法是:

Since the .live() method handles events once they have propagated to the top of the document, it is not possible to stop propagation of live events. Similarly, events handled by .delegate() will always propagate to the element to which they are delegated; event handlers on any elements below it will already have been executed by the time the delegated event handler is called.

由於我英文太爛,所以簡單來說是:叫傳播不要用自己的手機(疑)!

舉個簡單的例子來看:

<!DOCTYPE html>
<html>
    <head>
        <style>
            h3 { color:red; }
            span { color:green; }
        </style> 
        <script src="http://code.jquery.com/jquery-1.5.js"></script>
    </head>
    <body>
        <div id="workspace">
            <h3 class="live-event">Click me, by .live</h3>
            <h3 class="delegate-event">Click me, by .delegate</h3>
        </div>
        <script>
            $("#workspace").click(function(e) {
                e.stopPropagation();
                $(this).append("There is #workspace click event.<br />");
            }, false);
            $(".live-event").live("click", function(e){
                $(this).parent().append("<span>There is .live click event.</span><br />");
            }, false);
            $("#workspace").delegate(".delegate-event", "click", function(e) {
                $(this).parent().append("<span>There is .delegate click event.</span><br />");
            }, false);
        </script>
    </body>
</html>

這個例子可以去 http://jsfiddle.net/hinablue/KFkGZ/ 玩玩看。你會發現,一旦 .live 的父元件停止事件傳播(propagation)之後,整個 .live 就會停止動作。反觀 .delegate 則不受影響,這是唯一的差別。

另外,由於 .delegate 有老爸罩(?)的關係,所以在事件綁定上,速度與記憶體的使用量,要比直接使用 .live 要來的快,記憶體也用的比較少。所以,扣掉事件傳播這個可能需要考量的地方之外,如果要大量的綁定事件的話,建議使用 .delegate 會比 .live 要來得好得多。畢竟他跟 .live 效果是完全一樣的(扣掉事件傳播這件事情)。

至於,什麼時候該用 .live?這,請拿出兩個十元,然後平心境氣得往前扔,如果出現一正一反,那應該就可以用!如果發現兩顆硬幣站起來了,不要慌張,趕快看一下有什麼號碼,然後打電話給我!

我的電話在螢幕下方,請自便。

Hina Chen
偏執與強迫症的患者,算不上是無可救藥,只是我已經遇上我的良醫了。
Taipei