两者都是正确的,但它们本身都不是“最好的”,开发人员选择使用这两种方法可能是有原因的。
事件监听器(addEventListener
和 IE 的attachEvent
)
早期版本的 Internet Explorer 实现 JavaScript 的方式与几乎所有其他浏览器不同。对于版本低于 9 的版本,您可以使用attachEvent
[doc] 方法,像这样:
element.attachEvent('onclick', function() { /* do stuff here*/ });
在大多数其他浏览器(包括 IE 9 及更高版本)中,您使用addEventListener
[doc], 像这样:
element.addEventListener('click', function() { /* do stuff here*/ }, false);
使用这种方法(DOM 2 级事件),理论上您可以将无限数量的事件附加到任何单个元素。唯一的实际限制是客户端内存和其他性能问题,这对于每个浏览器来说都是不同的。
上面的例子代表使用匿名函数[doc]。您还可以使用函数引用添加事件侦听器[doc] 或闭包[doc]:
const myFunctionReference = function() { /* do stuff here*/ }
element.attachEvent('onclick', myFunctionReference);
element.addEventListener('click', myFunctionReference , false);
的另一个重要特点addEventListener
是最后一个参数,它控制监听器如何对冒泡事件做出反应[doc]。我在示例中传递了 false,这对于 95% 的用例来说是标准的。没有同等的论据attachEvent
,或者使用内联事件时。
内联事件(HTMLonclick=""
财产和element.onclick
)
在所有支持 JavaScript 的浏览器中,您可以内联事件侦听器,即直接在 HTML 代码中。您可能已经看过这个:
<a id="testing" href="#" onclick="alert('did stuff inline');">Click me</a>
大多数有经验的开发人员都会避开这种方法,但它确实可以完成工作;它简单而直接。您不能在这里使用闭包或匿名函数(尽管处理程序本身是某种匿名函数),并且您对范围的控制是有限的。
你提到的另一种方法:
element.onclick = function () { /*do stuff here */ };
... 相当于内联 JavaScript,只不过您可以更好地控制范围(因为您编写的是脚本而不是 HTML)并且可以使用匿名函数、函数引用和/或闭包。
内联事件的显着缺点是,与上述事件侦听器不同,您可能只分配了一个内联事件。内联事件存储为元素的属性/属性[doc],意味着它可以被覆盖。
使用示例<a>
从上面的 HTML 中:
const element = document.getElementById('testing');
element.onclick = function () { alert('did stuff #1'); };
element.onclick = function () { alert('did stuff #2'); };
...当您单击该元素时,您会only请参阅“Did stuff #2” - 您覆盖了第一个分配的onclick
属性具有第二个值,并且您覆盖了原始的内联 HTMLonclick
财产到.在这里查看:http://jsfiddle.net/jpgah/.
从广义上讲,不要使用内联事件。它可能有特定的用例,但如果您不能 100% 确定您有该用例,那么您不会也不应该使用内联事件。
现代 JavaScript(Angular 等)
自从这个答案最初发布以来,像 Angular 这样的 JavaScript 框架已经变得更加流行。您将在 Angular 模板中看到如下代码:
<button (click)="doSomething()">Do Something</button>
这看起来像一个内联事件,但事实并非如此。这种类型的模板将被转换为更复杂的代码,在幕后使用事件侦听器。我在这里写的有关事件的所有内容仍然适用,但您至少脱离了一层本质。您应该了解具体细节,但如果您的现代 JavaScript 框架最佳实践涉及在模板中编写此类代码,请不要觉得您正在使用内联事件 – 事实并非如此。
哪个最好?
问题是浏览器兼容性和必要性的问题。您是否需要将多个事件附加到一个元素?未来你会吗?很有可能,你会的。 AttachEvent 和 addEventListener 是必需的。如果没有,内联事件可能看起来可以解决问题,但你最好为未来做好准备,虽然这看起来不太可能,但至少是可以预测的。您有可能必须转向基于 JavaScript 的事件侦听器,因此您不妨从那里开始。不要使用内联事件。
jQuery 和其他 JavaScript 框架将 DOM 2 级事件的不同浏览器实现封装在通用模型中,因此您可以编写跨浏览器兼容的代码,而不必担心 IE 的历史。与 jQuery 相同的代码,所有跨浏览器并准备好摇滚:
$(element).on('click', function () { /* do stuff */ });
不过,不要仅仅为了这一件事就跑去获取一个框架。您可以轻松地推出自己的小实用程序来处理旧浏览器:
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!'); }
);
Try it: http://jsfiddle.net/bmArj/
考虑到所有这些,除非您正在查看的脚本以其他方式考虑了浏览器差异(在您的问题中未显示的代码中),否则使用的部分addEventListener
在低于 9 的 IE 版本中无法工作。
文档和相关阅读
- W3 HTML 规范,元素事件处理程序属性
- MDN 上的 element.addEventListener
- MSDN 上的 element.attachEvent
- jquery.com
- quirksmode博客“活动简介”
- Google 的 CDN 托管 JavaScript 库