addEventListener vs onclick

Wil*_*ham 642 javascript onclick addeventlistener

addEventListener和之间有什么区别onclick

var h = document.getElementById("a");
h.onclick = dothing1;
h.addEventListener("click", dothing2);
Run Code Online (Sandbox Code Playgroud)

上面的代码一起存在于一个单独的.js文件中,它们都完美地工作.

Chr*_*ker 896

两者都是正确的,但它们本身都不是"最佳",开发人员可能选择使用这两种方法.

事件监听器(addEventListener和IE的attachEvent)

早期版本的Internet Explorer实现javascript与几乎所有其他浏览器不同.对于小于9的版本,您使用attachEvent[ doc ]方法,如下所示:

element.attachEvent('onclick', function() { /* do stuff here*/ });
Run Code Online (Sandbox Code Playgroud)

在大多数其他浏览器(包括IE 9及更高版本)中,您使用addEventListener[ doc ],如下所示:

element.addEventListener('click', function() { /* do stuff here*/ }, false);
Run Code Online (Sandbox Code Playgroud)

使用此方法(DOM Level 2事件),您可以将理论上无限数量的事件附加到任何单个元素.唯一的实际限制是客户端内存和其他性能问题,每个浏览器都有所不同.

上面的示例表示使用匿名函数[ doc ].您还可以使用函数引用[ doc ]或闭包[ doc ] 添加事件侦听器:

var myFunctionReference = function() { /* do stuff here*/ }

element.attachEvent('onclick', myFunctionReference);
element.addEventListener('click', myFunctionReference , false);
Run Code Online (Sandbox Code Playgroud)

另一个重要特性addEventListener是最终参数,它控制侦听器对冒泡事件[ doc ]的反应.我在示例中传递了错误,这可能是95%的用例的标准.attachEvent使用内联事件时没有等效参数.

内联事件(HTML onclick =""property和element.onclick)

在所有支持javascript的浏览器中,您可以将事件侦听器内联,即HTML代码中的内容.你可能已经看到了这个:

<a id="testing" href="#" onclick="alert('did stuff inline');">Click me</a>
Run Code Online (Sandbox Code Playgroud)

大多数有经验的开发人员都避开这种方法,但它确实完成了工作; 它简单直接.你可能不会在这里使用闭包或匿名函数(虽然处理程序本身是各种类型的匿名函数),并且你对范围的控制是有限的.

你提到的另一种方法:

element.onclick = function () { /*do stuff here */ };
Run Code Online (Sandbox Code Playgroud)

...相当于内联javascript,除了你有更多的范围控制(因为你正在编写脚本而不是HTML),并且可以使用匿名函数,函数引用和/或闭包.

内联事件的显着缺点是,与上述事件侦听器不同,您可能只分配了一个内联事件.内联事件存储为元素[ doc ] 的属性/属性,这意味着它可以被覆盖.

使用<a>上面的HTML 示例:

var element = document.getElementById('testing');
element.onclick = function () { alert('did stuff #1'); };
element.onclick = function () { alert('did stuff #2'); };
Run Code Online (Sandbox Code Playgroud)

...当你点击元素时,你只会看到"Did stuff#2" - 你onclick用第二个值覆盖了第一个赋值的属性,并且你也覆盖了原始的内联HTML onclick属性.在这里查看:http://jsfiddle.net/jpgah/.

一般来说,不要使用内联事件.可能存在特定的用例,但如果您不是100%确定您拥有该用例,那么您不会也不应该使用内联事件.

现代Javascript(Angular之类)

由于这个答案最初发布,像Angular这样的javascript框架变得更加流行.你会在Angular模板中看到这样的代码:

<button (click)="doSomething()">Do Something</button>
Run Code Online (Sandbox Code Playgroud)

这看起来像一个内联事件,但事实并非如此.这种类型的模板将被转换为更复杂的代码,后者在幕后使用事件监听器.我在这里所写的关于事件的所有内容仍然适用,但是至少有一层将你从细节中删除.您应该了解这些细节,但如果您的现代JS框架最佳实践涉及在模板中编写此类代码,请不要觉得您正在使用内联事件 - 您不是.

哪个最好?

问题在于浏览器的兼容性和必要性.您当前是否需要将多个事件附加到元素?你将来会吗?赔率是,你会的.attachEvent和addEventListener是必要的.如果没有,内联事件可能看起来像他们会做的那样,但是你为未来做好准备,尽管看起来似乎不太可能,至少可以预测.有可能你必须转移到基于JS的事件监听器,所以你也可以从那里开始.不要使用内联事件.

jQuery和其他javascript框架在通用模型中封装了DOM 2级事件的不同浏览器实现,因此您可以编写跨浏览器兼容的代码,而无需担心IE作为反叛者的历史.与jQuery相同的代码,所有跨浏览器并准备好摇滚:

$(element).on('click', function () { /* do stuff */ });
Run Code Online (Sandbox Code Playgroud)

但是,不要为了这一件事而耗尽并获得一个框架.您可以轻松地滚动自己的小实用程序来处理旧版浏览器:

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!'); }
);
Run Code Online (Sandbox Code Playgroud)

试试吧:http://jsfiddle.net/bmArj/

考虑到所有这些因素,除非您正在查看的脚本以其他方式考虑浏览器差异(在您的问题中未显示的代码中),addEventListener否则使用的部分将无法在小于9的IE版本中使用.

文件和相关阅读

  • 抱歉,只是想给你的函数的浓缩版本(小提琴:http://jsfiddle.net/bmArj/153/) - `function addEvent(element,myEvent,fnc){return((element.attachEvent)? element.attachEvent('on'+ myEvent,fnc):element.addEventListener(myEvent,fnc,false)); }` (12认同)
  • @Gaurav_soni否.函数的名称及其包含的所有代码已经在javascript文件中公开,该文件是纯文本.任何人都可以打开Web控制台并执行或操作任何JavaScript.如果你的javascript包含任何可能存在安全风险的东西,如果它暴露给公众,那么你就会遇到一个重大问题,因为它已经暴露给公众. (8认同)
  • 只要我们凝聚这个算法,我们也可以一直走:`function addEvent(e,n,f){return e.attachEvent?e.attachEvent('on'+ n,f):e. addEventListener(n,f,!! 0)}`<< 98个字符,这个小于40%! (4认同)
  • @Trevor出于好奇,为什么!! 0?为什么不!1或只是0? (3认同)
  • @AdrianMoisa这个答案是在写的时候AngularJS在上升一个新的东西,和一般的做法仍然是"渐进增强" - 也就是说,在写作的方式,将有或没有工作的JavaScript的HTML文档.从这个角度来看,来自javascript的绑定事件将是最佳实践.如今,我不认为很多人会过分担心渐进式增强,尤其是不考虑像Angular这样的东西.关于内联事件(不使用Angular)的问题仍存在一些分离,但这种风格比实质更多. (2认同)
  • 我不同意,内联事件处理程序不仅更容易发现和维护 - 事实上,您永远不会遇到任何事件冒泡问题,这只是使工作更容易的另一件事。如果您确实需要多个处理程序来处理相同的元素和相同的事件,那么实际检查现有处理程序并不很难,只需包装/装饰它即可。现在在启蒙时代,它或多或少是被禁止的 - 你有诸如名为“js-click”的类或名为“data-whatever =“draggable””的属性之类的东西。在我看来,情况更糟,事件冒泡只会给我带来悲伤…… (2认同)

lon*_*day 170

如果您有另外两个功能,您可以看到差异:

var h = document.getElementById('a');
h.onclick = doThing_1;
h.onclick = doThing_2;

h.addEventListener('click', doThing_3);
h.addEventListener('click', doThing_4);
Run Code Online (Sandbox Code Playgroud)

功能2,3和4工作,但1不工作.这是因为addEventListener不会覆盖现有的事件处理程序,而是onclick覆盖任何现有的onclick = fn事件处理程序.

当然,另一个显着的区别是,它onclick始终有效,而addEventListener在版本9之前的Internet Explorer中不起作用.您可以在IE <9中使用类似的attachEvent(语法略有不同).

  • 这是一个非常明确的解释!正确的.因此,如果我需要多个函数用于一个事件,我会遇到addEventListener,我必须为attachEvent编写更多代码以容纳IE. (16认同)
  • 2,3和4应该命名为dosomething.1被2覆盖,永远不会被调用. (2认同)

Mic*_*ski 59

在这个答案中,我将描述定义DOM事件处理程序的三种方法.

element.addEventListener()

代码示例:

const element = document.querySelector('a');
element.addEventListener('click', event => event.preventDefault(), true);
Run Code Online (Sandbox Code Playgroud)
<a href="//google.com">Try clicking this link.</a>
Run Code Online (Sandbox Code Playgroud)

element.addEventListener() 有多重优势:

  • 允许您注册无限制的事件处理程序并将其删除element.removeEventListener().
  • useCapture参数,表示您是否想要在捕获或冒泡阶段处理事件.请参阅:无法理解addEventListener中的useCapture属性.
  • 关心语义.基本上,它使事件处理程序更明确地注册.对于初学者来说,函数调用很明显会发生某些事情,而将事件分配给DOM元素的某些属性至少是不直观的.
  • 允许您分离文档结构(HTML)和逻辑(JavaScript).在非常微小的Web应用程序可能似乎并不重要,但它与任何大项目的关系.维护一个分离结构和逻辑的项目比一个没有的项目要容易得多.
  • 消除与正确事件名称的混淆.由于使用内联事件侦听器或将事件侦听器分配给.oneventDOM元素的属性,许多没有经验的JavaScript程序员认为事件名称是例如onclickonload.on不是事件名称的一部分.正确的事件名称是clickload,以及事件名称的传递方式.addEventListener().
  • 适用于几乎所有浏览器.如果仍需要支持IE <= 8,则可以使用MDN中的polyfill.

element.onevent = function() {}(例如onclick,onload)

代码示例:

const element = document.querySelector('a');
element.onclick = event => event.preventDefault();
Run Code Online (Sandbox Code Playgroud)
<a href="//google.com">Try clicking this link.</a>
Run Code Online (Sandbox Code Playgroud)

这是一种在DOM 0中注册事件处理程序的方法.现在不鼓励这样做,因为它:

  • 允许您注册一个事件处理程序.删除指定的处理程序也不直观,因为要删除使用此方法分配的事件处理程序,您必须将onevent属性还原回其初始状态(即null).
  • 响应错误适当.例如,如果您错误地将字符串分配给window.onload,例如:window.onload = "test";,则不会抛出任何错误.你的代码不起作用,很难找到原因..addEventListener()然而,会抛出错误(至少在Firefox中):TypeError:EventTarget.addEventListener的参数2不是对象.
  • 如果要在捕获或冒泡阶段处理事件,则不提供选择方法.

内联事件处理程序(oneventHTML属性)

代码示例:

<a href="//google.com" onclick="event.preventDefault();">Try clicking this link.</a>
Run Code Online (Sandbox Code Playgroud)

与此类似element.onevent,现在不鼓励了.除了问题element.onevent,它:

  • 是一个潜在的安全问题,因为它使XSS更有害.现在,网站应该发送适当的Content-Security-PolicyHTTP标头来阻止内联脚本,并且只允许来自可信域的外部脚本.请参阅内容安全策略如何工作?
  • 分离文档结构和逻辑.
  • 如果使用服务器端脚本生成页面,例如生成一百个链接,每个链接具有相同的内联事件处理程序,则代码将比仅定义一次事件处理程序的代码长得多.这意味着客户端必须下载更多内容,结果您的网站会变慢.

也可以看看


Mag*_*nar 22

虽然onclick适用于所有浏览器,addEventListener但在旧版本的Internet Explorer中无法使用attachEvent.

缺点onclick是只能有一个事件处理程序,而其他两个将触发所有已注册的回调.


jAn*_*ndy 12

据我所知,DOM"加载"事件仍然只起作用非常有限.这意味着它只会火了window object,images<script>例如元素.直接onload分配也是如此.这两者之间没有技术差异.可能.onload =有更好的跨浏览器可用性.

但是,您无法将load eventa <div><span>元素或其他内容分配给.


t_d*_*m93 8

一个元素对于每种事件类型只能附加一个事件处理程序,但可以有多个事件侦听器


那么,它的实际效果如何呢?

仅运行分配的最后一个事件处理程序:

const button = document.querySelector(".btn")
button.onclick = () => {
  console.log("Hello World");
};
button.onclick = () => {
  console.log("How are you?");
};
button.click() // "How are you?" 
Run Code Online (Sandbox Code Playgroud)

所有事件监听器都会被触发:

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?"
Run Code Online (Sandbox Code Playgroud)

IE 注意:attachEvent不再支持。从 IE 11 开始,使用addEventListener: docs


Wil*_*een 6

摘要:

  1. addEventListener可以添加多个事件,而onclick不能这样做。
  2. onclick可以作为HTML属性添加,而addEventListener只能在<script>元素内添加。
  3. addEventListener 可以采用第三个参数来停止事件传播。

两者都可以用来处理事件。但是,它addEventListener应该是首选,因为它可以做所有事情onclick 以及更多。不要将内联onclick用作HTML属性,因为这会将javascript和HTML混合在一起,这是一种不好的做法。它使代码的可维护性降低。


a g*_*est 5

有一个细节没有注意到尚:现代桌面浏览器考虑不同的按键操作是“点击”了AddEventListener('click',并onclick在默认情况下。

  • 在Chrome 42和IE11,双方onclickAddEventListener单击火左边和中间点击。
  • 在Firefox 38,onclick触发在左侧点击,但AddEventListener点击左,中火右点击。

此外,当涉及滚动光标时,跨浏览器的中键行为非常不一致:

  • 在 Firefox 上,鼠标中键事件总是会触发。
  • 在 Chrome 上,如果鼠标中键打开或关闭滚动光标,它们将不会触发。
  • 在 IE 上,它们会在滚动光标关闭时触发,但不会在打开时触发。

还值得注意的是,任何可用键盘选择的 HTML 元素的“单击”事件,例如input也会在空格上触发或在元素被选择时输入。


Arh*_*ury 5

\n

element.onclick = function() { /* 做一些事情 */ }

\n

element.addEventListener(\'click\', function(){ /* 执行操作 */ },false);

\n
\n

他们显然做了同样的事情:监听点击事件并执行回调函数。然而,它们\xe2\x80\x99并不等效。如果您需要在两者之间进行选择,这可以帮助您找出最适合您的一个。

\n

主要区别在于onclick 只是一个属性,并且像所有对象属性一样,如果多次写入,它将被覆盖。使用addEventListener()代替,我们可以简单地绑定一个事件处理程序到元素,并且每次需要时都可以调用它,而不必担心任何属性被覆盖。\n示例如下所示,

\n

尝试一下: https: //jsfiddle.net/fjets5z4/5/

\n

首先,我很想继续使用 onclick,因为它 \xe2\x80\x99 更短,看起来更简单 \xe2\x80\xa6 事实上它是。但我不建议再使用它。它\xe2\x80\x99s 就像使用内联 JavaScript 一样。现在非常不鼓励使用像 \xe2\x80\x93 这样的东西,\xe2\x80\x99s 内联 JavaScript \xe2\x80\x93 (内联 CSS 也不鼓励,但是 \xe2\x80\x99s 是另一个主题)。

\n

然而,addEventListener() 函数尽管\xe2\x80\x99 是标准的,但在旧浏览器(版本 9 以下的 Internet Explorer)中不起作用,这是另一个很大的区别。如果你需要支持这些古老的浏览器,你应该遵循onclick方式。但您也可以使用 jQuery(或其替代方案之一):它基本上简化了您的工作并减少了浏览器之间的差异,因此可以节省您大量时间。

\n
var clickEvent = document.getElementByID("onclick-eg");\nvar EventListener = document.getElementByID("addEventListener-eg");\n\nclickEvent.onclick = function(){\n    window.alert("1 is not called")\n}\nclickEvent.onclick = function(){\n    window.alert("1 is not called, 2 is called")\n}\n\nEventListener.addEventListener("click",function(){\n    window.alert("1 is called")\n})\nEventListener.addEventListener("click",function(){\n    window.alert("2 is also called")\n})\n
Run Code Online (Sandbox Code Playgroud)\n


小智 5

您还应该考虑 EventDelegate!出于这个原因,我更喜欢 addEventListener 并且最重要的是仔细且有意识地使用它!

事实:

  1. 事件监听器很重....(客户端的内存分配)
  2. 事件相对于 DOM 树传播进来,然后再次传播出去。也称为滴入和冒泡,如果您不知道,请阅读它。

想象一个简单的例子:一个简单的按钮位于 div 内部的主体中...如果您单击按钮,事件无论如何都会流入 BUTTON,然后再次流出,如下所示:

窗口文档 div 按钮 div 文档窗口

在浏览器后台(比如说 JS 引擎的软件外围),如果浏览器检查目标位置上的每次点击,它只能对点击做出反应。

为了确保触发途中每个可能的事件侦听器,它必须将“单击事件信号”从文档级别一直发送到元素......然后再次返回。然后可以通过附加 EventListeners 使用此行为,例如:

document.getElementById("exampleID").addEventListener("click",(event) => {doThis}, true/false);
Run Code Online (Sandbox Code Playgroud)

请注意,作为 addEventListener 方法的最后一个参数的 true/false 控制事件何时被识别的行为 - 当滴入或冒泡时。

TRUE 表示事件在滴入时被识别 FALSE 表示事件在冒泡时被识别

使用上述处理方法来实现以下两个有用的概念也变得更加直观:

  1. event.stopPropagation()您还可以在函数内使用(示例参考“doThis”)来防止当前事件在捕获和冒泡阶段进一步传播。然而,它并不能阻止任何默认行为的发生;例如,仍然会处理链接的点击。
  2. 如果您想停止这些行为,您可以 event.preventDefault()在函数内使用(示例参考“doThis”)。例如,您可以告诉浏览器,如果事件没有得到显式处理,则不应像通常那样采取其默认操作。

另外请注意此处再次参考:addEventListener 方法的最后一个参数(true/false)还控制“.stopPropagation()”的最终效果在哪个阶段(滴入 TRUE 或冒泡出 FALSE)生效。所以。 ..如果您将带有 TRUE 标志的 EventListener 应用于元素,并将其与 .stopPropagation() 方法结合使用,该事件甚至不会到达该元素的潜在内部子元素

总结一下:如果您在 HTML 中使用 onClick 变体...对我来说有 2 个缺点:

  1. 使用 addEventListener,您可以将多个 onClick 事件分别附加到同一个元素,但使用 onClick 是不可能的(至少这是我到目前为止坚信的,如果我错了,请纠正我)。
  2. 另外,以下方面在这里确实值得注意......尤其是代码维护部分(到目前为止尚未详细说明):

关于事件委托,实际上可以归结为这一点。如果其他一些 JavaScript 代码需要响应单击事件,则使用 addEventListener 可确保双方都可以响应它。如果你们都尝试使用 onclick,那么一个会踩到另一个。如果您想要对同一元素进行 onclick,则双方都无法响应。Furthermore, you want to keep your behavior as separate as you can from the HTML in case you need to change it later. It would suck to have 50 HTML files to update instead of one JavaScript file. (归功于 Greg Burghardt,addEventListener 与 onclick 关于事件委托的比较

  • 这也被称为“Unobtrusive JavaScript”这个术语……读一下!