問題:
addEventListener 和 onclick 有什么不同嗎渊额?
var h=document.getElementById("a");
h.onclick=dothing1;
h.addEventListener("click", dothing2);
上面的代碼放到了一個獨立的.js文件中况木,并且都運行正常旬迹。
高票答案:
這兩種方式都是正確的,但是沒有一個本質上是“最佳”奔垦,而且開發(fā)者可能有恰當的理由選擇同時使用這兩種方法。
事件監(jiān)聽器 (addEventListener 和 IE中的attachEvent)
IE早期版本對JS的實現(xiàn)和其它任何瀏覽器都有著相當大的差距椿猎。在版本<9的情況下惶岭,你需要使用attachEvent
[doc]方法,就像這樣:
element.attachEvent('onclick', function() { /* 在這兒做點什么*/ });
在大部分其它的瀏覽器中(包括IE9及以上)按灶,你需要使用addEventListener
[doc]方法, 就像這樣:
element.addEventListener('click', function() { /* 在這兒做點什么*/ }, false);
通過使用這個方法 (DOM Level 2 events), 你理論上能夠給單個元素附加無限數量的事件監(jiān)聽器。實際上唯一的限制就是客戶端的內存和其它性能因素鸯旁,這在每個瀏覽器上都各不相同。
上面的例子代表著使用一個匿名函數[doc]. 你也可以使用一個函數引用作為事件監(jiān)聽器[doc] 或者是一個閉包[doc]:
var myFunctionReference = function() { /* do stuff here*/ }
element.attachEvent('onclick', myFunctionReference);
element.addEventListener('click', myFunctionReference , false);
addEventListener
的另一個重要特性就是它最后的那個參數摩疑,該參數控制著監(jiān)聽器如何應答冒泡事件[doc]. 上面的例子里面,我傳遞了false
畏铆,這大概在95%的用例上都是標準用法。對于attachEvent
或者內聯(lián)事件辞居,并沒有與之對等的參數可供使用。
內聯(lián)事件 (HTML 的onclick=""屬性 和 element.onclick)
在所有支持JS的瀏覽器中瓦灶,你可以內聯(lián)的設置一個事件監(jiān)聽器,意味著寫在HTML代碼里贼陶。你也可能已經見過這種寫法:
<a id="testing" href="#" onclick="alert('did stuff inline');">Click me</a>
大部分有經驗的開發(fā)者會避開這種寫法,不過它確實能夠達成目標:簡單且直接碉怔。你在這不能使用閉包或者匿名函數(即使handler函數某種意義上就是一個匿名函數),并且你對作用域的控制是有限的撮胧。
你提到的另一種方法:
element.onclick = function () { /*do stuff here */ };
同內聯(lián)方式基本相同,除了你能對作用域有更多的控制(因為相較于純HTML芹啥,你此刻寫的是一段腳本),你也可以使用匿名函數墓怀、函數引用和閉包汽纠。
內聯(lián)事件明顯的一個缺點就是不像我們上面說的那幾種一樣傀履,你一次只能分配一個內聯(lián)事件。內聯(lián)事件被作為元素上的一個屬性/特性[doc], 這意味著它能夠被重寫。
使用上述HTML例子中的<a>
元素:
var element = document.getElementById('testing');
element.onclick = function () { alert('did stuff #1'); };
element.onclick = function () { alert('did stuff #2'); };
...當你點擊這個元素的時候卧秘,你只能看到"Did stuff #2",因為后面的賦值把前面的onclick
覆蓋了翅敌,同時也覆蓋了HTML上原生的onclick
屬性。在這里查看demo: http://jsfiddle.net/jpgah/.
哪個是最好的?
答案是看瀏覽器兼容性和需要蚯涮。你當前是否需要為一個元素添加多個事件監(jiān)聽器?將來呢遭顶?多半是這樣的。attachEvent
和 addEventListener
是必須的棒旗。如果不需要,那么內聯(lián)事件將擔此重任铣揉。
jQuery和其它JS框架為不同的瀏覽器封裝了一套通用的DOM level 2 events實現(xiàn),所以你可以不用擔心IE的歷史問題搗亂了逛拱,安心寫跨瀏覽器一致的代碼。相同的功能用jQuery寫, 當當當當朽合!:
$(element).on('click', function () { /* do stuff */ });
但是俱两,請不要為了這一件小事就引入了一個框架曹步。你可以輕松的實現(xiàn)一個自己的小工具庫來處理老瀏覽器上的問題:
function addEvent(element, evnt, funct){
if (element.attachEvent)
return element.attachEvent('on'+evnt, funct);
else
return element.addEventListener(evnt, funct, false);
}
// example
addEvent(
document.getElementById('myElement'),
'click',
function () { alert('hi!'); }
);
來這兒試試: http://jsfiddle.net/bmArj/
要把上面所有的因素都考慮進來,除非你以某種其它的方式考慮瀏覽器的差異化(你問題中的代碼可能沒體現(xiàn)出來),那就是IE9 以下addEventListener
不被支持箭窜。
文檔和相關參考閱讀
W3 HTML specification, element Event Handler Attributes
element.addEventListener on MDN
element.attachEvent on MSDN
Jquery.on
quirksmode blog "Introduction to Events"
CDN-hosted javascript libraries at Google