建議的解決方案是定義一個通用的事件路由器對象,它為目標元素附加一個 標準函數,作為一個事件回調,並且維護一個監聽器函數的列表。這允許我們以 下面的方式重寫mousemat的初始化代碼:
window.onload=function(){
var mat=document.getElementById('mousemat');
...
var mouseRouter=new jsEvent.EventRouter(mat,"onmousemove");
mouseRouter.addListener(writeStatus);
mouseRouter.addListener (drawThumbnail);
}
我們定義了一個EventRouter對象,傳入DOM元素並希望註冊為參數的事件類別 型。然後向路由器對象增加監聽器函數,路由器對象也支援removeListener()方 法,這裡我們不需要該方法。這個對象看起來很直接,但是我們如何?它呢?
首先,我們為對象編寫一個建構函式,這在JavaScript中僅僅是一個函數(附 錄B包含了JavaScript對象文法的初級教程。如果不明白下面的代碼,可以參考 該教程)。
jsEvent.EventRouter=function(el,eventType){
this.lsnrs=new Array();
this.el=el;
el.eventRouter=this;
el[eventType] =jsEvent.EventRouter.callback;
}
我們定義了監聽器函數的數組(最初它是空的),儲存了一個到DOM元素的引用 ,並且使用3.5.1節描述的模式給DOM元素添加了一個到這個對象的引用。然後我 們分配一個EventRouter類的靜態函數,簡單地稱作callback,作為事件處理函 數。記住在JavaScript中,方括弧和點記號是等同的,這意味著: el.onmouseover和el['onmouseover']是相同的。為使用方便,我們將屬性名稱 作為參數傳遞進來。這與Java或者.NET語言的反射是類似的。
然後,讓我們看看callback:
jsEvent.EventRouter.callback=function(event){
var e=event || window.event;
var router=this.eventRouter;
router.notify(e)
}
因為這是一個回呼函數,函數上下文是觸發事件的DOM節點,而不是路由器對 象。我們使用前面提到的後端對象模式得到已經附加在 DOM 節點上的 EventRouter的引用,然後調用路由器的notify()方法,將事件對象作為參數傳 遞進來。
EventRouter對象的完整代碼如代碼清單4-8所示。