挖掘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來顯示)。