addEventListener
和onclick
之间有什么区别?
var h = document.getElementById("a");
h.onclick = dothing1;
h.addEventListener("click", dothing2);
上面的代码一起存放在一个单独的.js文件中,它们都可以很好地工作。
答案 0 :(得分:851)
两者都是正确的,但它们本身都不是“最佳”,开发人员可能选择使用这两种方法。
事件监听器(addEventListener和IE的attachEvent)
早期版本的Internet Explorer与其他几乎所有浏览器的实现方式不同。对于小于9的版本,您使用attachEvent
[doc]方法,如下所示:
element.attachEvent('onclick', function() { /* do stuff here*/ });
在大多数其他浏览器(包括IE 9及更高版本)中,您使用addEventListener
[doc],如下所示:
element.addEventListener('click', function() { /* do stuff here*/ }, false);
使用这种方法(DOM Level 2 events),您可以将理论上无限数量的事件附加到任何单个元素。唯一的实际限制是客户端内存和其他性能问题,每个浏览器都有所不同。
上面的示例表示使用匿名函数[doc]。您还可以使用函数引用[doc]或闭包[doc]添加事件侦听器:
var myFunctionReference = function() { /* do stuff here*/ }
element.attachEvent('onclick', myFunctionReference);
element.addEventListener('click', myFunctionReference , false);
addEventListener
的另一个重要特性是最终参数,它控制侦听器对冒泡事件[doc]的反应。我在示例中传递了错误,这可能是95%的用例的标准。 attachEvent
或使用内联事件时没有等效参数。
内联事件(HTML onclick =“”property and 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>
:
var element = document.getElementById('testing');
element.onclick = function () { alert('did stuff #1'); };
element.onclick = function () { alert('did stuff #2'); };
...当你点击元素时,你只看到“没有东西#2” - 你用第二个值覆盖了onclick
属性的第一个分配,并且您也覆盖了原始内联HTML onclick
属性。请在此处查看:http://jsfiddle.net/jpgah/。
一般来说,不使用内联事件。可能有特定的用例,但如果您不是100%确定您拥有该用例,那么您不会也不应该使用内联事件。
现代Javascript(Angular等)
由于这个答案最初发布,像Angular这样的javascript框架变得更加流行。你会在Angular模板中看到这样的代码:
<button (click)="doSomething()">Do Something</button>
这看起来像是内联事件,但事实并非如此。这种类型的模板将被转换为更复杂的代码,后者在幕后使用事件监听器。我在这里所写的关于事件的所有内容仍然适用,但是至少有一层你被从细节中删除了。您应该了解这些细节,但如果您的现代JS框架最佳实践涉及在模板中编写此类代码,请不要觉得您正在使用内联事件 - 您不是。
哪个最好?
问题在于浏览器的兼容性和必要性。您当前是否需要将多个事件附加到元素?你将来会吗?赔率是,你会的。 attachEvent和addEventListener是必要的。如果没有,内联事件可能看起来像他们会做的那样,但是你为未来做好准备,尽管看起来似乎不太可能,至少可以预测。有可能你必须转移到基于JS的事件监听器,所以你也可以从那里开始。不要使用内联事件。
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
的部分在IE中不起作用小于9的版本。
文档及相关阅读
答案 1 :(得分:153)
如果你有另外两个功能,你可以看到差异:
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工作,但1不工作。这是因为addEventListener
不会覆盖现有的事件处理程序,而onclick
会覆盖任何现有的onclick = fn
事件处理程序。
另一个显着的区别当然是onclick
将始终有效,而addEventListener
在版本9之前的Internet Explorer中不起作用。您可以使用类似的attachEvent
(在IE&lt; 9。
答案 2 :(得分:54)
在这个答案中,我将描述定义DOM事件处理程序的三种方法。
element.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
参数,表示您是否要在捕获或冒泡阶段中处理事件。请参阅:Unable to understand useCapture attribute in addEventListener。.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>
这是一种在DOM 0中注册事件处理程序的方法。现在不鼓励这样做,因为它:
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标头来阻止内联脚本,并且只允许来自可信域的外部脚本。请参阅How does Content Security Policy work? 答案 3 :(得分:20)
虽然onclick
适用于所有浏览器,但addEventListener
在旧版本的Internet Explorer中不起作用,而后者使用的是attachEvent
。
onclick
的缺点是只能有一个事件处理程序,而其他两个将触发所有已注册的回调。
答案 4 :(得分:12)
据我所知,DOM“加载”事件仍然只能起到非常有限的作用。这意味着它只会触发window object
,images
和<script>
元素。直接onload
分配也是如此。这两者之间没有技术差异。可能.onload =
具有更好的跨浏览器可用性。
但是,您无法将load event
分配给<div>
或<span>
元素或其他内容。
答案 5 :(得分:4)
addEventListener
可以添加多个事件,而使用onclick
则无法完成。onclick
可以作为HTML
属性添加,而addEventListener
只能在<script>
元素内添加。addEventListener
可以采用第三个参数,该参数可以停止事件传播。两者均可用于处理事件。但是,addEventListener
应该是首选,因为它可以完成onclick
做的所有事情,甚至更多。不要将内联onclick
用作HTML属性,因为这会混淆javascript和HTML,这是一种不好的做法。它使代码的可维护性降低。
答案 6 :(得分:2)
根据 MDN ,差异如下:
<强>的addEventListener:强>
EventTarget.addEventListener()方法添加指定的 EventListener兼容对象的事件侦听器列表 在其上调用的EventTarget上指定的事件类型。该 事件目标可以是文档中的元素,文档本身,a 窗口或支持事件的任何其他对象(例如 XMLHttpRequest的)。
<强>的onclick:强>
onclick属性返回on上的click事件处理程序代码 当前元素。使用click事件触发操作时也是如此 考虑将这个相同的动作添加到keydown事件,以允许 不使用鼠标或触摸的人使用相同的动作 屏幕。语法element.onclick = functionRef;其中functionRef是一个 function - 通常是在别处或函数中声明的函数的名称 表达。请参阅&#34; JavaScript指南:功能&#34;详情。
如下面的代码所示,使用中还存在语法差异:
的的addEventListener:强>
// Function to change the content of t2
function modifyText() {
var t2 = document.getElementById("t2");
if (t2.firstChild.nodeValue == "three") {
t2.firstChild.nodeValue = "two";
} else {
t2.firstChild.nodeValue = "three";
}
}
// add event listener to table
var el = document.getElementById("outside");
el.addEventListener("click", modifyText, false);
<强>的onclick:强>
function initElement() {
var p = document.getElementById("foo");
// NOTE: showAlert(); or showAlert(param); will NOT work here.
// Must be a reference to a function name, not a function call.
p.onclick = showAlert;
};
function showAlert(event) {
alert("onclick Event detected!");
}
答案 7 :(得分:2)
element.onclick = function(){/ *做东西* /}
element.addEventListener('click',function(){/ *做东西* /},false);
它们显然做同样的事情:监听click事件并执行回调函数。不过,它们并不相等。如果您需要在两者之间进行选择,这可以帮助您确定哪一个最适合您。
主要区别在于 onclick只是一个属性,并且像所有对象属性一样,如果多次写入,则会被覆盖。使用 addEventListener()代替,我们可以简单地绑定事件处理程序到元素,并且我们可以在每次需要它时调用它,而不必担心任何被覆盖的属性。 示例如下所示,
尝试:https://jsfiddle.net/fjets5z4/5/
首先,我很想继续使用onclick,因为它更短,看起来更简单……实际上是这样。但我不建议再使用它。就像使用内联JavaScript。如今,强烈建议不要使用内联JavaScript之类的东西(也不推荐内联CSS,但这是另一个主题)。
但是,尽管是标准功能,但addEventListener()函数在旧版浏览器(版本9以下的Internet Explorer)中仍然无法使用,这是另一个很大的不同。如果需要支持这些古老的浏览器,则应遵循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")
})
答案 8 :(得分:1)
如果您不太担心浏览器支持,有一种方法可以在事件调用的函数中重新绑定'this'引用。它通常指向执行函数时生成事件的元素,这并不总是您想要的。棘手的部分是同时能够删除相同的事件监听器,如下例所示:http://jsfiddle.net/roenbaeck/vBYu3/
/*
Testing that the function returned from bind is rereferenceable,
such that it can be added and removed as an event listener.
*/
function MyImportantCalloutToYou(message, otherMessage) {
// the following is necessary as calling bind again does
// not return the same function, so instead we replace the
// original function with the one bound to this instance
this.swap = this.swap.bind(this);
this.element = document.createElement('div');
this.element.addEventListener('click', this.swap, false);
document.body.appendChild(this.element);
}
MyImportantCalloutToYou.prototype = {
element: null,
swap: function() {
// now this function can be properly removed
this.element.removeEventListener('click', this.swap, false);
}
}
上面的代码在Chrome中运行良好,并且可能会出现一些与其他浏览器兼容的“绑定”问题。
答案 9 :(得分:1)
使用内联处理程序与Content Security Policy不兼容,因此addEventListener
方法从这个角度来看更安全。当然,您可以使用unsafe-inline
启用内联处理程序,但顾名思义,它不安全,因为它会带回CSP阻止的大量JavaScript漏洞利用。
答案 10 :(得分:1)
尚未注意到一个细节:现代桌面浏览器认为默认情况下,AddEventListener('click'
和onclick
按下不同的按钮是“点击”。
onclick
和AddEventListener
点击左侧和中间点击。onclick
在左键单击时仅触发 ,但AddEventListener
点击左侧,中间和右键点击。此外,当涉及滚动游标时,浏览器中的中间点击行为非常不一致:
值得注意的是,任何键盘可选HTML元素(如input
)的“点击”事件也会在空格上触发,或者在选择元素时输入。
答案 11 :(得分:1)
也应该可以通过原型化来扩展监听器(如果我们有一个对它的引用而不是一个匿名函数) - 或者让'onclick'调用一个函数库(一个函数调用其他函数)功能)
像
elm.onclick = myFunctionList
function myFunctionList(){
myFunc1();
myFunc2();
}
这意味着我们永远不必改变onclick调用只是改变函数myFunctionList()来做任何我们想要的事情,但是这让我们无法控制冒泡/捕获阶段,所以应该避免使用较新的浏览器。
以防有人在将来找到这个帖子......
答案 12 :(得分:0)
我猜 Chris Baker 在一个很好的答案中总结了它,但我想通过 addEventListener() 添加到它,您还可以使用 options 参数让您更好地控制您的事件。例如 - 如果您只想运行一次您的事件,那么您可以在添加您的事件以仅调用一次时使用 { once: true } 作为选项参数。
function greet() {
console.log("Hello");
}
document.querySelector("button").addEventListener('click', greet, { once: true })
上述函数只会打印一次“Hello”。 此外,如果您想清除事件,则还可以选择 removeEventListener()。尽管使用 addEventListener() 有很多优点,但是如果您的目标受众使用 Internet Explorer,您仍然应该小心,那么此方法可能不适用于所有情况。您还可以在 MDN 上阅读 addEventListener,他们对如何使用它们做了很好的解释。
答案 13 :(得分:0)
addEventListener
允许您设置多个处理程序,但IE8或更低版本不支持。
IE确实有attachEvent
,但它并不完全相同。
答案 14 :(得分:0)
let element = document.queryselector('id or classname');
element.addeventlistiner('click',()=>{
do work
})
<button onclick="click()">click</click>`
function click(){
do work
};
答案 15 :(得分:0)
答案 16 :(得分:0)
每个事件类型的元素只能附加一个事件处理程序,但是可以具有多个事件侦听器。
那么,它的实际效果如何?
仅运行最后分配的事件处理程序:
const btn = document.querySelector(".btn")
button.onclick = () => {
console.log("Hello World");
};
button.onclick = () => {
console.log("How are you?");
};
button.click() // "Hello World"
所有事件监听器都会被触发:
const btn = 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
:docs。
答案 17 :(得分:0)
Javascript倾向于将所有内容混合到对象中,这可能会让人感到困惑。一切都是JavaScript方式。
基本上onclick是一个HTML属性。相反,addEventListener是DOM对象上表示HTML元素的方法。
在JavaScript对象中,方法只是一个属性,它具有一个作为值的函数,并且对其所附加的对象起作用(例如,使用它)。
在JavaScript中,由DOM表示的HTML元素将其属性映射到其属性。
这是人们感到困惑的地方,因为JavaScript将所有内容融合到一个没有间接层的单个容器或命名空间中。
在正常的OO布局中(至少合并属性/方法的命名空间),您可能会遇到类似的情况:
domElement.addEventListener // Object(Method)
domElement.attributes.onload // Object(Property(Object(Property(String))))
有些变体可能会使用getter / setter进行onload或HashMap进行属性,但最终会看起来如何。 JavaScript消除了那个间接层,期望知道什么是其他东西。它将domElement和属性合并在一起。
除了兼容性之外,您应该使用addEventListener作为最佳实践。由于其他答案谈到了这方面的差异而不是基本的程序差异,我将放弃它。从本质上讲,在一个理想的世界中,你真的只是想在HTML中使用*,但在一个更理想的世界中,你不应该从HTML那样做。
为什么它今天占据主导地位?写作更快,更容易学习,而且往往只是工作。
HTML中onload的重点是首先提供对addEventListener方法或功能的访问。通过在JS中使用它,当您可以直接应用它时,您将通过HTML。
假设您可以创建自己的属性:
$('[myclick]').each(function(i, v) {
v.addEventListener('click', function() {
eval(v.myclick); // eval($(v).attr('myclick'));
});
});
JS所做的与此有点不同。
你可以把它等同于(对于每个创建的元素):
element.addEventListener('click', function() {
switch(typeof element.onclick) {
case 'string':eval(element.onclick);break;
case 'function':element.onclick();break;
}
});
实际的实施细节可能会因一系列微妙的变化而有所不同,使得两者在某些情况下略有不同,但这是它的要点。
可以说是一个兼容性黑客,你可以将一个函数固定到一个on属性,因为默认属性都是字符串。
答案 18 :(得分:-1)
JavasSript中'this'
关键字引用的上下文不同。
查看以下代码:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
</head>
<body>
<input id="btnSubmit" type="button" value="Submit" />
<script>
function disable() {
this.disabled = true;
}
var btnSubmit = document.getElementById('btnSubmit');
btnSubmit.onclick = disable();
//btnSubmit.addEventListener('click', disable, false);
</script>
</body>
</html>
它的作用非常简单。当您单击该按钮时,该按钮将自动禁用。
首先,当您尝试以这种方式连接事件时button.onclick = function(),
单击按钮将触发onclick事件,但是,按钮不会被禁用,因为button.onclick和onclick事件处理程序之间没有明确的绑定。如果您调试,请参阅'this'
对象,您可以看到它引用'window'
对象。
其次,如果您评论btnSubmit.onclick = disable();
并取消注释
//btnSubmit.addEventListener('click', disable, false);
您可以看到该按钮被禁用,因为这种方式在button.onclick事件和onclick事件处理程序之间存在显式绑定。如果您调试为禁用功能,则可以看到'this'
引用button control
而不是window
。
这是我不喜欢的JavaScript,这是不一致的。
顺便说一句,如果你使用jQuery($('#btnSubmit').on('click', disable);
),它使用显式绑定。
答案 19 :(得分:-2)
onclick本质上是一个addEventListener,它在单击元素时专门执行一个功能。因此,当您具有执行简单操作的按钮(例如计算器按钮)时很有用。 addEventlistener可用于多种操作,例如在加载DOM或所有内容时执行操作,类似于window.onload,但具有更多控制权。
请注意,实际上,您可以内联使用多个事件,或者至少可以通过用分号分隔每个函数来使用onclick,例如...。
我不会用内联编写函数,因为稍后您可能会遇到问题,而且imo会很乱。只需使用它来调用脚本文件中已完成的功能即可。
我想您使用哪一个取决于您想要的。 addEventListener用于复杂操作,onclick用于简单操作。我已经看到一些项目没有将特定项目附加到元素上,而是实现了一个更具全局性的事件侦听器,该事件侦听器将确定是否在按钮上轻按,并根据所按的内容执行某些任务。 Imo可能会导致我认为的问题,而且即使事件侦听器必须处理每一次单击,也可能会造成资源浪费,尽管这可能很小,但是