addEventListener与onclick的区别

980

addEventListeneronclick 有什么区别?

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

上述代码位于单独的 .js 文件中,它们都能完美地工作。

21个回答

4
JavaScript倾向于将所有内容混合到对象中,这可能会让人感到困惑。将所有内容混合到一个对象中是JavaScript的方式。
基本上,onclick是一个HTML属性。相反,addEventListener是表示HTML元素的DOM对象上的方法。
在JavaScript对象中,方法只是具有函数值的属性,并针对其所附加到的对象(例如使用this)工作。
在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中使用on*,但在更理想的情况下,你不应该在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属性上是一种兼容性hack,因为默认情况下属性都是字符串。


3
根据MDN的说明,它们之间的区别如下:
addEventListener:
EventTarget.addEventListener()方法将指定的EventListener兼容对象添加到调用它的EventTarget上指定事件类型的事件监听器列表中。事件目标可以是文档中的元素、文档本身、窗口或支持事件的任何其他对象(例如XMLHttpRequest)。
onclick:
onclick属性返回当前元素上的单击事件处理程序代码。当使用单击事件触发操作时,还应考虑将同样的操作添加到keydown事件中,以允许不使用鼠标或触摸屏幕的人使用相同的操作。语法为element.onclick = functionRef;其中functionRef是一个函数——通常是在其他地方声明的函数名称或函数表达式。有关详细信息,请参见"JavaScript Guide:Functions"。
您还可以在下面的代码中看到使用上的语法差异:
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!");
}

2

我想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的内容,他们对如何使用它们给出了相当好的解释。


1
这是很棒的信息!在我回答的时候,选项参数并不存在。我正在考虑更新我的答案,并链接到这个答案以引用这个较新的信息。好答案 :) - Chris Baker

1

如果我们有一个监听器的引用,而且它不是匿名函数,那么我们还可以通过原型扩展监听器;或者让onclick调用一个函数库(一个调用其他函数的函数)。

例如:

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

这意味着我们永远不需要更改onclick调用,只需改变函数myFunctionList()以实现任何想要的功能,但这会使我们失去冒泡/捕获阶段的控制,因此应避免在较新的浏览器中使用。

1
使用内联处理程序与 内容安全策略不兼容,因此从这个角度来看,addEventListener方法更加安全。当然,您可以使用unsafe-inline启用内联处理程序,但正如其名称所示,它不安全,因为它会带回整个JavaScript漏洞,而CSP则可以防止这些漏洞。

2
注意:此安全限制仅适用于扩展开发,并且链接文档中提供的安全理由主要仅适用于浏览器扩展开发。然而,链接文档中提到的一个点对于Web开发也是正确的,那就是将内容与行为分离。这是整个领域的良好实践。 - Chris Baker

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中运行良好,可能有一些支架使"bind"与其他浏览器兼容。


0

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

IE 有 attachEvent,但并非完全相同。


-1

onclick基本上是一个addEventListener,它在元素被点击时执行特定的函数。因此,当您有一个执行简单操作的按钮(如计算器按钮)时非常有用。 addEventlistener可以用于许多事情,例如在DOM或所有内容加载时执行操作,类似于window.onload但具有更多控制。

请注意,您实际上可以使用多个事件来进行内联,或者至少通过使用onclick将每个函数分隔开来使用分号,就像这样...

我不会使用内联编写函数,因为您可能以后会遇到问题,并且我认为这会很混乱。只需使用它来调用已在脚本文件中完成的函数即可。

我想要使用哪个取决于您想要什么。addEventListener用于复杂操作,onclick用于简单操作。我看过一些项目没有将特定的元素附加到元素上,而是实现了一个更全局的eventlistener,该eventlistener将确定是否在按钮上轻敲并根据按下的内容执行某些任务。在我看来,这可能会导致问题,并且尽管很小,但可能会浪费资源,如果该eventlistener必须处理每次单击。


-1

'this' 关键字在 JavaScript 中所引用的上下文是不同的。

请看以下代码:

<!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事件处理程序之间存在明确的绑定。如果您调试进入disable函数,您可以看到'this'引用按钮控件而不是window

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


9
你需要写成 btnSubmit.onclick = disable; (赋值函数,不要调用它)。这样,在两种情况下,this将引用按钮元素。 - Pasha

-2
在我的 Visual Studio Code 中,addEventListener 在事件上具有真正的智能感知

enter image description here

但是 onclick 不行,只有假的

enter image description here


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接