JavaScript作為一門基於事件驅動的語言(特別是用在DOM操作的時候),我們常常需要為DOM綁定各種各樣的事件。然而,由於低版本的IE的不給力,在綁定事件和移除事件監聽上都與眾不同,我們常常需要自己封裝一個跨瀏覽器綁定(移除)事件的函數。跨瀏覽器添加(移除)DOM事件的一種非常經典的實現代碼如下:
//跨瀏覽器添加事件 function addHandler(target, eventType, handler) { if(target.addEventListener) { //DOM2 events target.addEventListener(eventType, handler, false); } else { //IE target.attachEvent("on" + eventType, handler); } } //跨瀏覽器移除事件 function removeHanler(target, eventType, handler) { if(target.removeEventListener) { //DOM2 events target.removeEventListener(eventType, handler, false); } else { //IE target.detachEvent("on", eventType, handler); } }
上面代碼的實現思路是,首先判斷瀏覽器是否支持DOM2的事件,如果支持,就用addEventListener()進行添加事件,用removeEventListener來移除事件。如果不支持,那么默認就是低版本的ie瀏覽器了,並使用ie特有的方法。
乍一看,上面的代碼好像已經充分優化了。隱藏的性能問題在於
每次函數調用時都會做重復工作——檢測瀏覽器的類型。這是比較消耗性能,特別是你綁定大量事件,反復調用的時候。事實上,這是不必要的,我們只需要判斷一次就行的了。因為一旦頁面加載完成后,瀏覽器的類型已經是確定了的,不可能說,現在是IE,然后瀏覽着瀏覽着突然就會變成了chrome的了。所以,我們應該對上面代碼進行優化,使其只需要檢測一次瀏覽器。有兩種方法可以實現只檢測一次,下面分別來探討一下這兩種方法。
第一種是,在第一次調用添加(移除)事件函數的時候,檢測並決定使用哪種方法來綁定或者移除事件,然后重寫函數,用一個包含正確操作的新的函數覆蓋舊的函數,
並且在舊的函數最后調用該這個新的函數。上面代碼改寫后如下:
//添加事件 function addHandler(target, eventType, handler) { //檢測瀏覽器類型,並且重寫addHanler方法 if(target.addEventListener) { //DOM2 addHandler = function(target, eventType, handler) { target.addEventListener(eventType, handler, false); }; } else { //IE addHandler = function(target, eventType, handler) { target.attachEvent("on" + eventType, handler); }; } //調用新的函數 addHandler(target, eventType, handler); } //移除事件removeHanler function removeHandler(target, eventType, handler) { //檢測瀏覽器類型,並且重寫removeHandler方法 if(target.removeEventListener) { //DOM2 removeHandler = function(target, eventType, handler) { target.removeEventListener(eventType, handler, false); }; } else { //IE removeHandler = function(target, eventType, handler) { target.detachEvent("on" + eventType, handler); }; } //調用新的函數 removeHandler(target, eventType, handler); }
需要注意的是,我們在兩個函數的最后一行,都調用了被重寫了的新函數,比如addHandler(target, eventType, handler);和removeHandler(target, eventType, handler);這是必要的,因為我們用新的函數覆蓋了舊的函數,必須要在舊的函數里調用新的函數它才會執行一次。
還有一種優化方法是,提前檢測瀏覽器類型,並把正確的操作函數賦值給一個變量(或者說是使用函數表達式)。我們可以使用一個三目條件運算符(?...:)來實現,代碼如下:
//綁定事件 var addHandler = document.body.addEventListener ? function(target, eventType, handler) { //DOM2 target.addEventListener(eventType, handler,false); } : function(target, eventType, handler) { //IE target.attachEvent("on" + eventType, handler); };
//移除事件 var removeHandler = document.body.removeEventListener ? function(target, eventType, handler) { //DOM2 target.removeEventListener(eventType, handler, false); } : function(target, eventType, handler) { //IE target.detachEvent("on" + eventType, handler); }
這種方法,比前面比前面那種更加的“積極”,因為他是在函數調用之前就已經去檢測瀏覽器類型了,調用的時候馬上就可以正確的去綁定事件。
PS:
參考資料:
Nicbolas C.Zakas 《High Performance JavaScript》;chapter 8 ;Don’t Repeat Work
該書目前好像只有英文版而還沒有中文版的。如果有需要的可以Google一下,下載個電子版的來看一下