挖掘jQuery的事件管理機制

 Thu, 27 Nov 2008 17:13:25 +0800

之前因為好奇,稍微trace了一下jQuery的事件管理機制。在看過原始碼跟檢查過jQuery處理過的node之後,寫了一個小程式來取出掛在node上的事件處理函數。

<html>
<script src="js/jquery-1.2.6.js"></script>
<body>
<div id="panel">test</div>
<div id="target">target</div>
<script>
$("#panel").click(function(e){
    for(var i in this) {
        if(i.indexOf("jQuery")==0) {
            var tmp = this[i];
        }
    }
    var ret = '<table border="1" cellspacing="0" cellpadding="2">';
    for (var i in $.cache[tmp]['events']['click']) {
        ret += '<tr><td>' + i + ':</td><td>' + $.cache[tmp]['events']['click'][i] + '</td></tr>';
    }
    ret += '</table>';
    this.innerHTML = ret;
    alert($.event.guid);
});
$("#panel").click(function(e){
    alert(this);
});
$("#target").click(function(e){
    alert('target');
});
$("#panel").click(function(e){
    alert('test');
});
$("#target").click(function(e){
    for(var i in this) {
        if(i.indexOf("jQuery")==0) {
            var tmp = this[i];
        }
    }
    var ret = '<table border="1" cellspacing="0" cellpadding="2">';
    for (var i in $.cache[tmp]['events']['click']) {
        ret += '<tr><td>' + i + ':</td><td>' + $.cache[tmp]['events']['click'][i] + '</td></tr>';
    }
    ret += '</table>';
    this.innerHTML = ret;
    alert($.event.guid);
});
</script>
</body>
</html>

 

簡單地說,jQuery是在一個匿名函數裡面建立他的程式庫。jquery載入時會在那個匿名函數裡面產生一個區域變數叫做expando,在node上面操作時,會為node加入一個attribute,名稱是expando的值,這個attribute的值是來自在匿名函數裡面的另一個區域變數叫做uuid,jQuery會用遞增的方式維護,讓每個node會有一個unique的值來對應管理。另外$.event.guid是個由jquery維護的索引,每加一個event handler就會遞增。

jquery還是用addEventListener或attachEvent來為node加入事件,把eventlistener 存在$.cache裡面,我想是為了要能removeEventListener,因為需要用到同一個函數的 reference才有辦法做。但是如果用匿名函數當作event handler,之後就會碰到無法移除的問題。

DOM2 event跟DOM3 event都沒有一個可以在node上查詢已掛上事件處理函數的機制,所以就非得自己管理不可了。上面的code簡單示範如何從$.cache裡面取出掛在node上的事件處理函數,只是有點粗略(我沒有用textnode來顯示)。