addEventListener
和 onclick
有什么区别?
var h = document.getElementById("a");
h.onclick = dothing1;
h.addEventListener("click", dothing2);
上述代码位于单独的 .js
文件中,它们都能完美地工作。
addEventListener
和 onclick
有什么区别?
var h = document.getElementById("a");
h.onclick = dothing1;
h.addEventListener("click", dothing2);
上述代码位于单独的 .js
文件中,它们都能完美地工作。
这两种方法都是正确的,但并没有“最佳”一说,开发者选择使用这两种方法可能有其原因。
addEventListener
和IE的attachEvent
)早期版本的Internet Explorer与几乎所有其他浏览器实现JavaScript不同。在小于9的版本中,您可以使用attachEvent
[doc]方法,如下所示:
element.attachEvent('onclick', function() { /* do stuff here*/ });
addEventListener
[doc],如下所示:element.addEventListener('click', function() { /* do stuff here*/ }, false);
使用这种方法(DOM Level 2事件),您可以将理论上无限数量的事件附加到任何单个元素。唯一的实际限制是客户端内存和其他性能问题,这些问题对于每个浏览器都不同。
上面的示例代表了使用匿名函数[文档]。您还可以使用函数引用[文档]或闭包[文档]添加事件侦听器:
const myFunctionReference = function() { /* do stuff here*/ }
element.attachEvent('onclick', myFunctionReference);
element.addEventListener('click', myFunctionReference , false);
addEventListener
的另一个重要特性是最后一个参数,它控制侦听器如何响应冒泡事件[doc]。在示例中,我一直传递false,这是大概95%使用情况的标准。对于attachEvent
或使用内联事件时,没有等效的参数。
onclick=""
属性和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],这意味着它可能会被覆盖。
使用上面HTML中的<a>
示例:
const element = document.getElementById('testing');
element.onclick = function () { alert('did stuff #1'); };
element.onclick = function () { alert('did stuff #2'); };
...当你点击元素时,你只会看到“Did stuff #2” - 你用第二个值覆盖了onclick
属性的第一个赋值,并且也覆盖了原始的内联HTML onclick
属性。在这里查看:http://jsfiddle.net/jpgah/。
总的来说,不要使用内联事件。可能有特定的用例,但如果你不确定是否有这种用例,那么你就没有并且不应该使用内联事件。
自从这个回答最初发布以来,像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!'); }
);
试一下:http://jsfiddle.net/bmArj/
考虑到所有这些,除非你查看的脚本以某种其他方式(在你的问题中未显示的代码中)考虑了浏览器差异,否则使用addEventListener
的部分将无法在低于9版本的IE中工作。
文档和相关阅读
如果你有另外两个函数,你就能看到它们之间的区别:
var h = document.getElementById('a');
h.onclick = doThing_1;
h.onclick = doThing_2;
h.addEventListener('click', doThing_3);
h.addEventListener('click', doThing_4);
第 2、3 和 4 个函数可以正常工作,但第一个函数不能。这是因为 addEventListener
不会覆盖现有的事件处理程序,而 onclick
会覆盖任何现有的 onclick = fn
事件处理程序。
当然,另一个重要的区别是,onclick
总是可用的,而 addEventListener
在 Internet Explorer 9 版本之前不起作用。在 IE <9 中,您可以使用类似的 attachEvent
(语法略有不同)。
element.onclick = myFunction
,那么当HTML未显示时,它将不会被清除,实际上,您可以将事件附加到从未添加到DOM的元素(因此它们是页面的“一部分”)。在许多情况下,如果您附加了这样的事件,它可能会留下一个打开的引用,因此它不会被GC清除。 - Chris Baker<html>
元素中添加一个addEventListener()
,然后只需检查event.target
属性即可监听特定元素的点击事件。这样我就不必担心用流氓事件侦听器污染内存堆。它以前是内联的(在HTML中定义),即使它随着元素被删除而被删除,它仍会占用内存空间...对吗? - Ludolfynelement.addEventListener()
const element = document.querySelector('a');
element.addEventListener('click', event => event.preventDefault(), true);
<a href="//google.com">Try clicking this link.</a>
element.addEventListener()
具有多个优点:
element.removeEventListener()
将它们删除。useCapture
参数,表示您想在其捕获或冒泡阶段处理事件。请参见:无法理解addEventListener中useCapture属性。.onevent
属性,许多经验不足的 JavaScript 程序员认为事件名称例如为onclick
或onload
。 on
不是事件名称的一部分。正确的事件名称是click
和load
,并且这就是如何将事件名称传递给.addEventListener()
。element.onevent = function() {}
(例如onclick
,onload
)代码示例:
const element = document.querySelector('a');
element.onclick = event => event.preventDefault();
<a href="//google.com">Try clicking this link.</a>
onevent
属性恢复到其初始状态(即null
)。window.onload
,例如:window.onload = "test";
,它不会抛出任何错误。您的代码将无法工作,很难找出原因。然而,.addEventListener()
会抛出错误(至少在Firefox中):TypeError:EventTarget.addEventListener的第2个参数不是对象。onevent
HTML属性)代码示例:
<a href="//google.com" onclick="event.preventDefault();">Try clicking this link.</a>
与element.onevent
类似,现在不鼓励使用。除了element.onevent
存在的问题外,它还有以下问题:
Content-Security-Policy
HTTP头来阻止内联脚本,并仅允许来自受信任域的外部脚本。参见Content Security Policy如何工作?虽然所有浏览器都支持onclick
,但旧版的Internet Explorer不支持addEventListener
而是使用attachEvent
。
onclick
的缺点是只能有一个事件处理程序,而其他两个会触发所有已注册的回调函数。
addEventListener
可以添加多个事件,而使用onclick
则无法做到。onclick
可以作为HTML
属性添加,而addEventListener
只能在<script>
元素中添加。addEventListener
可以采用第三个参数来停止事件传播。两者都可用于处理事件。然而,addEventListener
应该是首选,因为它可以做到onclick
的所有功能并且更多。不要将行内onclick
用作HTML属性,因为这将混淆javascript和HTML,这是一个不好的做法。这会使代码难以维护。
onclick
处理程序,因为我害怕被嘲笑 - 但通常事件绑定的方式在最近几年中变得更糟糕和难以维护。像js-link
、js-form-validation
这样的类或带有data-jspackage="init"
的数据属性并不比内联处理程序好多少...你实际上有多频繁地使用事件冒泡呢?我个人希望能够编写一个处理程序,而无需检查目标是否实际上与我的元素匹配 - 或者由于随机错误而不得不在多个位置停止传播。 - Christoffer Bubachul
标签上放置一个单独的事件侦听器。单击任何包含的 li
元素会冒泡到此 ul
事件侦听器。然后,您使用 event.target
确定单击了哪个 li
元素,然后从那里开始。如果不使用冒泡,则必须为每个 li
元素放置单独的事件侦听器。 - BobRodeswindow对象
、images
和<script>
等元素的事件。直接使用onload
赋值也是如此。这两者之间没有技术上的区别。可能.onload=
在跨浏览器可用性方面更好。load事件
分配给<div>
或<span>
元素或其他任何元素。那么,它在实践中是什么样子?
只有最后一个被指定的事件处理程序会运行:
const button = document.querySelector(".btn")
button.onclick = () => {
console.log("Hello World");
};
button.onclick = () => {
console.log("How are you?");
};
button.click() // "How are you?"
所有的事件监听器都会被触发:
const button = document.querySelector(".btn")
button.addEventListener("click", event => {
console.log("Hello World");
})
button.addEventListener("click", event => {
console.log("How are you?");
})
button.click()
// "Hello World"
// "How are you?"
IE的注意事项: attachEvent
不再受支持。从IE 11开始,请使用addEventListener
:文档。
还有一个细节需要注意:现代桌面浏览器默认情况下认为不同的按钮按下对于AddEventListener('click'
和onclick
来说是不同的“点击”。
onclick
和AddEventListener
都会在左键和中键单击时触发点击事件。onclick
仅在左键单击时触发,但AddEventListener
点击事件会在左键、中键和右键单击时触发。此外,当涉及滚动光标时,中键行为非常不一致:
值得注意的是,任何可用键盘选择的HTML元素(例如input
)的“点击”事件在选定元素时也会在空格或回车键按下时触发。
document.getElementById("exampleID").addEventListener("click",(event) => {doThis}, true/false);
请注意,addEventListener方法的最后一个true/false参数控制事件何时被识别——是在冒泡过程中还是在捕获过程中。
true表示在冒泡过程中识别事件
false表示在冒泡过程中识别事件
使用上述方法处理还可以更加直观地实现以下两个有用的概念:
event.stopPropagation()
(例如参考“doThis”)来防止当前事件在捕获和冒泡阶段进一步传播。但它不会阻止任何默认行为发生;例如,链接点击仍然会被处理。event.preventDefault()
(例如参考“doThis”)。这样,您可以告诉浏览器,如果事件没有被明确处理,它的默认操作不应像通常那样被执行。element.onclick = function() { /* do stuff */ }
element.addEventListener('click', function(){ /* do stuff */ },false);
这两个方法都可以监听点击事件并执行回调函数,但它们并不相等。如果你需要选择其中一个,下面的内容可能会帮到你。
最主要的区别是onclick只是一个属性,就像所有对象属性一样,如果你多次写入,它将被覆盖。而使用addEventListener(),我们可以为元素简单地绑定一个事件处理程序,每次需要时都可以调用它,无需担心任何被覆盖的属性。 示例如下:
试一试:https://jsfiddle.net/fjets5z4/5/
一开始我很想继续使用onclick,因为它更短,看起来更简单… 实际上确实如此。但我不再推荐使用它了。它就像使用内联JavaScript一样。现在已经非常不鼓励使用这种方式(内联CSS也不鼓励使用,但那是另一个话题)。
然而,尽管addEventListener()是标准,它在旧浏览器(Internet Explorer 9版本以下)中并不起作用,这是另一个重要的区别。如果你需要支持这些古老的浏览器,你应该使用onclick。但你也可以使用jQuery(或其替代品):它基本上简化了你的工作并减少了浏览器之间的差异,因此可以节省你很多时间。
var clickEvent = document.getElementByID("onclick-eg");
var EventListener = document.getElementByID("addEventListener-eg");
clickEvent.onclick = function(){
window.alert("1 is not called")
}
clickEvent.onclick = function(){
window.alert("1 is not called, 2 is called")
}
EventListener.addEventListener("click",function(){
window.alert("1 is called")
})
EventListener.addEventListener("click",function(){
window.alert("2 is also called")
})
function addEvent(element, myEvent, fnc) { return ((element.attachEvent) ? element.attachEvent('on' + myEvent, fnc) : element.addEventListener(myEvent, fnc, false)); }
。该函数用于添加事件监听器。 - Deryckfunction addEvent(e,n,f){return e.attachEvent?e.attachEvent('on'+n,f):e.addEventListener(n,f,!!0)}
。这个函数只有98个字符,比原来的算法缩小了40%以上! - Trevor