addEventListener vs onclick

addEventListeneronclick什么区别?

 var h = document.getElementById("a"); h.onclick = dothing1; h.addEventListener("click", dothing2); 

上面的代码驻留在一个单独的.js文件中,并且它们都可以很好地工作。

两者都是正确的,但是它们本身都不是“最好的”,开发者可能会select使用这两种方法。

事件监听器(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 ]。 您还可以使用函数reference [ doc ]或闭包[ doc ]添加事件侦听器:

 var myFunctionReference = function() { /* do stuff here*/ } element.attachEvent('onclick', myFunctionReference); element.addEventListener('click', myFunctionReference , false); 

addEventListener另一个重要特性是最终的参数,它控制了监听器如何对冒泡事件做出反应[ doc ]。 在这个例子中,我一直使用false,这个例子大概是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'); }; 

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

哪个最好?

问题是浏览器兼容性和必要性的问题。 你目前是否需要在一个元素上附加多个事件? 你会在未来吗? 赔率是,你会的。 attachEvent和addEventListener是必需的。 如果没有的话,一个内联事件就可以做到这一点。

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

 $(element).on('click', function () { /* do stuff */ }); 

尽pipe如此,不要为了这一点而耗尽框架。 您可以轻松地推出自己的小工具来照顾旧版浏览器:

 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版本。

文档和相关阅读

  • W3 HTML规范,元素事件处理程序属性
  • MDN上的element.addEventListener
  • MSDN上的element.attachEvent
  • Jquery.on
  • quirksmode博客“事件简介”
  • 在谷歌C​​DN托pipe的JavaScript库

你可以看到,如果你有另外几个function的区别:

 var h = document.getElementById('a'); h.onclick = donothing1; h.onclick = donothing2; h.addEventListener('click', donothing3); h.addEventListener('click', donothing4); 

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

另一个显着的不同点是, onclick将始终工作,而addEventListener在版本9之前的Internet Explorer中不起作用。您可以在IE <9中使用类似的attachEvent (语法略有不同)。

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

element.addEventListener()

代码示例:

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

虽然onclick可以在所有浏览器中使用,但addEventListener在Internet Explorer的旧版本中不起作用,而Internet Explorer则使用attachEvent

onclick的缺点是只能有一个事件处理程序,而另外两个会触发所有已注册的callback。

据我所知,DOM“加载”事件仍然只能工作非常有限。 这意味着它只会触发window objectimages<script>元素。 直接在线分配也是如此。 这两者之间没有技术上的区别。 可能.onload =有更好的跨浏览器可用性。

但是,您无法将load event分配给<div><span>元素或其他元素。

如果您不太担心浏览器支持,则可以通过事件调用的函数重新绑定“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中运行良好,并且可能会使其他浏览器与“绑定”兼容。

使用内联处理程序与内容安全策略不兼容,所以addEventListener方法从这个angular度来看更安全。 当然,你可以使内联处理程序的内联unsafe-inline但顾名思义,这不是安全的,因为它带回了CSP阻止的整个JavaScript漏洞利用。

一个细节还没有被注意到:现代桌面浏览器认为不同的button是AddEventListener('click' “点击” AddEventListener('click'默认为AddEventListener('click'onclick

  • 在Chrome 42和IE11上, onclickAddEventListener点击左侧和中间点击。
  • 在Firefox 38上, onclick 在左键单击时触发,但AddEventListener点击左键,中键右键单击。

另外,当涉及到滚动游标时,跨浏览器的中点击行为是非常不一致的:

  • 在Firefox上,中点击事件总是触发。
  • 在Chrome上,如果middleclick打开或closures滚动光标,它们将不会触发。
  • 在IE浏览器中,当光标closures时会触发,但在打开时不会触发。

还值得注意的是,对于任何键盘可选的HTML元素(例如input “单击”事件也会在空间上触发,或者在select该元素时进行input。

也应该可以通过原型扩展监听器(如果我们有一个引用而不是一个匿名函数) – 或者使onclick调用一个函数库调用(一个调用其他函数的函数)

喜欢

  elm.onclick = myFunctionList function myFunctionList(){ myFunc1(); myFunc2(); } 

这意味着我们永远不需要调用onclick调用,只是改变函数myFunctionList()来做我们想做的事情,但是这使得我们无法控制冒泡/捕捉阶段,所以应该避免使用新的浏览器。

以防万一有人在未来find这个线程…

addEventListener可以设置多个处理程序,但在IE8或更低版本中不受支持。

IE确实有attachEvent ,但不完全一样。

JavaScript倾向于将所有东西都混合到对象中,这可能会让人困惑。 一切都是JavaScript的方式。

本质上onclick是一个HTML属性。 相反,addEventListener是表示HTML元素的DOM对象的一种方法。

在JavaScript对象中,一个方法仅仅是一个具有函数作为值的属性,并且与它所连接的对象(例如使用这个)相对立。

在JavaScript中,由DOM表示的HTML元素将其属性映射到其属性上。

这是人们感到困惑的地方,因为JavaScript将所有东西融合到一个没有间接层的容器或命名空间中。

在一个正常的OO布局(至less合并属性/方法的命名空间),你可能会有这样的:

 domElement.addEventListener // Object(Method) domElement.attributes.onload // Object(Property(Object(Property(String)))) 

有一些变化就像它可以使用一个getter / setter的onload或HashMap的属性,但最终这就是它的样子。 JavaScript期望知道除了其他事情之外,JavaScript消除了这个间接层。 它将domElement和属性合并在一起。

除了兼容性,你应该使用addEventListener作为最佳实践。 正如其他答案所谈到的那样,在这方面的分歧,而不是根本的纲领性差异,我会放弃它。 本质上,在一个理想的世界里,你真的只是用来从HTML中使用*,但在一个更理想的世界里,你不应该像从HTML那样做任何事情。

为什么今天占主导地位? 写起来更快,学习起来更容易,而且往往只是工作。

在HTML中加载的重点是首先访问addEventListener方法或function。 通过在JS中使用它,你可以直接应用HTML。

假设你可以做出自己的属性:

 $('[myclick]').each(function(i, v) { v.addEventListener('click', function() { eval(v.myclick); // eval($(v).attr('myclick')); }); }); 

JS所做的有点不同。

你可以把它等同于(为每个创build的元素):

 element.addEventListener('click', function() { switch(typeof element.onclick) { case 'string':eval(element.onclick);break; case 'function':element.onclick();break; } }); 

实际的实施细节可能会有一些微妙的差异,使得两者在某些情况下略有不同,但这是它的要点。

这可以说是一个兼容性破解,你可以将一个函数固定在on属性上,因为默认情况下属性都是string。

根据MDN,差异如下:

的addEventListener:

EventTarget.addEventListener()方法将指定的与EventListener兼容的对象添加到调用EventTarget的指定事件types的事件侦听器列表中。 事件目标可以是文档中的元素,文档本身,窗口或任何其他支持事件的对象(如XMLHttpRequest)。

的onclick:

onclick属性返回当前元素上的click事件处理程序代码。 当使用click事件触发一个动作的时候,也可以考虑在keydown事件中添加同样的动作,以允许不使用鼠标或触摸屏的人使用同样的动作。 语法element.onclick = functionRef; 其中functionRef是一个函数 – 通常是在其他地方声明的函数的名称或函数expression式。 有关详细信息,请参阅“JavaScript指南:函数”。

在下面的代码中,还有一个使用中的语法差异:

的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!"); } 

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时,button将被自动禁用。

首先,当你尝试以这种方式button.onclick = function(),事件button.onclick = function(), onclick事件将通过点击button触发,但是,该button不会被禁用,因为没有明确的button.onclick和onclick事件之间的绑定处理程序。 如果你debugging看到这个'this'对象,你可以看到它指的是'window'对象。

其次,如果你评论btnSubmit.onclick = disable(); 并取消注释//btnSubmit.addEventListener('click', disable, false); 您可以看到该button被禁用,因为通过这种方式,button.onclick事件和onclick事件处理程序之间存在显式绑定。 如果您debugging到禁用function,您可以看到'this'是指button control而不是window

这是我不喜欢JavaScript不一致的东西。 顺便说一句,如果您使用jQuery( $('#btnSubmit').on('click', disable); ),它使用显式绑定。