addEventListener 与 onclick

IT技术 javascript onclick addeventlistener
2021-03-06 21:28:12

什么之间的区别addEventListeneronclick

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

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

6个回答

两者都是正确的,但它们本身都不是“最好的”,开发人员选择使用这两种方法可能是有原因的。

事件监听器(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 Level 2 events),您可以将理论上无限数量的事件附加到任何单个元素。唯一的实际限制是客户端内存和其他性能问题,每个浏览器都不同。

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

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

element.attachEvent('onclick', myFunctionReference);
element.addEventListener('click', myFunctionReference , false);

的另一个重要特性addEventListener是 final 参数,它控制侦听器如何对冒泡事件作出react[ doc ]。我一直在示例中传递 false,这对于大约 95% 的用例来说是标准的。attachEvent, 或使用内联事件时没有等效的参数

内联事件(HTML onclick="" 属性和 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 ]的属性/属性,这意味着它可以被覆盖。

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

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

...当您单击该元素时,您只会看到“Did stuff #2” - 您onclick用第二个值覆盖了属性的第一个分配,并且您也覆盖了原始的内联 HTMLonclick属性。在这里查看: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否则使用的部分将无法在低于 9 的 IE 版本中使用

文档和相关阅读

@Gaurav_soni 不。函数的名称和它包含的所有代码已经在javascript文件中公开了,它是纯文本的。任何人都可以打开 Web 控制台并执行或操作任何 javascript。如果您的 javascript 包含任何可能对公众造成安全风险的内容,那么您就有了一个重大问题,因为它已经向公众公开了。
2021-04-20 21:28:12
只要我们压缩这个算法,我们还不如一路走下去:function addEvent(e,n,f){return e.attachEvent?e.attachEvent('on'+n,f):e.addEventListener(n,f,!!0)}<< 98个字符,这个小了40%以上!
2021-05-03 21:28:12
@AdrianMoisa 这个答案是在 AngularJS 还是一个新兴事物的时候写的,通常的做法仍然是“渐进式增强”——也就是说,以一种可以使用或不使用 javascript 的方式编写 HTML 文档。从这个角度来看,来自 javascript 的绑定事件将是最佳实践。现在,我认为很多人都不太担心渐进增强,尤其是没有考虑到像 Angular 这样的东西的流行。关于内联事件(不使用 Angular),仍然存在一些关注点分离,但这更多的是风格而不是实质。
2021-05-03 21:28:12
抱歉撞了,但只是想提供您的功能的精简版本(小提琴:jsfiddle.net/bmArj/153)-function addEvent(element, myEvent, fnc) { return ((element.attachEvent) ? element.attachEvent('on' + myEvent, fnc) : element.addEventListener(myEvent, fnc, false)); }
2021-05-07 21:28:12
@Trevor 出于好奇,为什么 !!0?为什么不是 !1 或只是 0?
2021-05-15 21:28:12

如果您有另外几个功能,您可以看到不同之处:

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 中不起作用。您可以在 IE <9 中使用类似的attachEvent语法略有不同)。

在某些情况下,使用 addEventListener 添加的事件也需要清理。
2021-04-29 21:28:12
@Ludolfyn 我想明确一点——如果内联事件是在 HTML 中定义的,那么在大多数情况下,当 HTML 离开浏览器视图时,它会被清除。如果您在代码中执行此操作element.onclick = myFunction,则不会在未显示 HTML 时清除该内容,事实上,您可以将事件附加到从未添加到 DOM 的元素(因此它们是页面的“一部分”)。在许多情况下,如果你附加一个这样的事件,它会留下一个开放的引用,所以它不会被 GC 清理。
2021-05-04 21:28:12
这是一个非常清楚的解释!说到点子上了。因此,如果我需要为一个事件提供多个函数,我会坚持使用 addEventListener,并且我必须为 attachEvent 编写更多代码以适应 IE。
2021-05-05 21:28:12
2、3 和 4 应命名为 dosomething。1 被 2 覆盖并且永远不会被调用。
2021-05-05 21:28:12
非常感谢@ChrisBaker!我仍在开发与此相关的应用程序,因此这非常有帮助。我是动态生成和清除进出DOM元素,所以我选择了跟着作出反应的配方中添加一个addEventListener()<html>元素,然后就检查event.target属性为侦听特定元素的点击次数。这样我就不必担心流氓事件侦听器会污染内存堆。它曾经是内联的(在 HTML 中定义),即使它被元素删除,它仍然占用内存空间......对吗?
2021-05-16 21:28:12

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

element.addEventListener()

代码示例:

element.addEventListener() 具有多重优势:

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

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

代码示例:

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

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

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

代码示例:

与 类似element.onevent,现在不鼓励使用。除了存在的问题外element.onevent,它还:

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

也可以看看

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

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

概括:

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

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

元素定位主要是如何完成的?我的意思是,我个人不会onclick因为害怕被人嘲笑而使用内联处理程序 - 但近年来事件通常以更糟糕和更少维护的方式受到约束。js-link,js-form-validation或 data 属性这样的类data-jspackage="init"绝对没有比这更好的了……您实际使用事件冒泡的频率有多少?我个人希望能够在不检查目标是否真的与我的元素匹配的情况下编写处理程序 - 或者由于随机错误而不得不在多个地方停止传播。
2021-05-07 21:28:12