addEventListener vs onclick
addEventListener
和onclick
什么区别?
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博客“事件简介”
- 在谷歌CDN托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 object
, images
和<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上,
onclick
和AddEventListener
点击左侧和中间点击。 - 在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);
),它使用显式绑定。