回归原生javascript,addEventListener 和 onclick 到底有什么不同?
前景
用习惯了JQ,对JQ的事件绑定和处理,相信大家已经是不陌生了,或许大家已经把原js生都抛之脑后了吧,不管是用什么框架,都是离不开原生js,所以建议大家还是对原生的多一些研究比较好!
问题描述
1 | var h = document.getElementById("a"); |
代码同时保存在一个分离的 .js 文件里面,而且它们都能完美地运行。
最佳答案
它们都是正确的,它们之间没有哪个是“最好的”,而且开发者有可能同时使用这两个方法。
事件监听器(Event Listeners,包括 addEventListener 以及 IE 的 attacheEvent)
旧版本的 IE 在执行 Javascript 时与几乎所有其它浏览器不同,在 IE 9 之前的版本中,你需要使用attachEvent模块,就像这样:
1 | element.attachEvent('onclick', function() { /* do stuff here*/ }); |
在大部分其它浏览器(包括 IE 9 以及更新的版本)中,你可以使用 addEventListener,就像这样:
1 | element.addEventListener('click', function() { /* do stuff here*/ }, false); |
使用这些方法(DOM2 事件),理论上你可以向某个元素加入无数的事件。但实际上,这会受限于客户端的内存容量以及其它的性能问题,而这对于每一个浏览器都是不同的。
1 | var myFunctionReference = function(){ /* do stuff here */ } |
addEventListener还有一个特点就是最后的参数,它会控制监听器在事件冒泡阶段时就作出反应。有大约 95% 的可能会像我在例子中那样使用 false。这个参数在 attachEvent 中或在使用内联事件(inline Events) 时没有等效的参数。
内联事件 (Inline Events, 即 HTML 中的 onclick=”” 属性 和 element.onclick)
在所有支持 Javascript 的浏览器中,你可以将一个事件监听器内联,也就是像下面的 HTML 代码那样:
1 | <a id="testing" href="#" onclick="alert('did stuff inline');">Click me</a> |
虽然它的确是可以完成任务的,而且简单直接,但绝大部分有经验的开发者都会尽量避开使用这样的方法。同时,你不能在这里使用闭包或者匿名函数(虽然处理程序本身就是一个匿名函数),而且你的控制范围是有限的。
另一个方法是这样的(也就是你提到的):
1 | element.onclick = funtion () { /* do stuff here */ } |
实际上这等价于内联 Javascript (也就是上面那种在 HTML 标签属性中添加的方法),不过这样可以拥有更大的控制范围,同时可以使用匿名函数、函数表达式或闭包。
内联事件有个重大的缺点就是,不像上面提到的事件监斩器那样,你只可以指定一个内联事件。内联事件会转化元元素的属性,那意味着当指定多个的内联事件时,它之前所指定的内联事件会被覆盖掉。
使用上面 HTML 代码中的<a>
标签来举个例子:
1 | var element = document.getElementById('testing'); |
当你点击这个元素后,你只可以看到 “Did stuff #2”,原因是第二个值覆盖了第一个指定的 onclick 属性,同时,会把 HTML 中 onclick 属性也覆盖掉。
二者谁更好呢?
主要的问题是浏览器兼容性和必要性。你目前是否需要添加一个以上的事件到一个元素上?未来是否需要?大部分时候,你是需要的。所以,使用attachEvent和addEventListener 是非常有必要的,不然用内联事件就好了。
JQuery 以及很多其它的 Javascript 框架都为不同的浏览器封装了通用的处理 DOM2 事件的通用模型(Models),这样你可以在做跨浏览器兼容时不需要为 IE 的历史遗留问题而烦恼了。同样的代码在 jQuery 中做跨浏览器兼容,只需要这样:
1 | $(element).on('click', function () { /* do stuff */ }); |
当然了,不要因为这么一件事而使用一个框架。你可以很容易地写出一个小工具来兼容旧版本的浏览器:
1 | function addEvent(element, evnt, funct){ |
综上,除非你看的这段脚本用其他方法处理了不同浏览器之间的差异 ,使用addEventListener的部分不会在 IE 9 以下的 IE 工作。