addEventListener vs onclick

时间:2011-06-14 18:49:54

标签: javascript onclick addeventlistener

addEventListeneronclick之间有什么区别?

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

上面的代码一起存放在一个单独的.js文件中,它们都可以很好地工作。

20 个答案:

答案 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
  • 关注语义。基本上,它使事件处理程序更明确地注册。对于初学者来说,函数调用很明显发生了某些事情,而将事件分配给DOM元素的某些属性至少是不直观的。
  • 允许您分隔文档结构(HTML)和逻辑(JavaScript)。在微小的Web应用程序中,它似乎并不重要,但它确实对任何更大的项目都很重要。维护一个分离结构和逻辑的项目要比没有项目的项目容易得多。
  • 消除与正确事件名称的混淆。由于使用内联事件侦听器或将事件侦听器分配给DOM元素的.onevent属性,许多缺乏经验的JavaScript程序员认为事件名称是例如onclickonload on 是事件名称的一部分。正确的事件名称为clickload,这就是事件名称传递给.addEventListener()的方式。
  • 适用于almost all browser。如果您仍需要支持IE&lt; = 8,则可以使用a polyfill from MDN

element.onevent = function() {}(例如onclickonload

代码示例:

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所具有的问题外,还有:

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

另见

答案 3 :(得分:20)

虽然onclick适用于所有浏览器,但addEventListener在旧版本的Internet Explorer中不起作用,而后者使用的是attachEvent

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

答案 4 :(得分:12)

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

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

答案 5 :(得分:4)

摘要:

  1. addEventListener可以添加多个事件,而使用onclick则无法完成。
  2. onclick可以作为HTML属性添加,而addEventListener只能在<script>元素内添加。
  3. 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按下不同的按钮是“点击”。

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

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

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

值得注意的是,任何键盘可选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)

在我的Visual Studio代码中,addEventListener在事件上具有 Real Intellisense

enter image description here

但onclick不会,只有伪造的

enter image description here

答案 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开始,请使用addEventListenerdocs

答案 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可能会导致我认为的问题,而且即使事件侦听器必须处理每一次单击,也可能会造成资源浪费,尽管这可能很小,但是