协慌网

登录 贡献 社区

addEventListener 与 onclick

addEventListeneronclick什么区别?

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

上面的代码一起驻留在单独的. js 文件中,并且它们都可以正常工作。

答案

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

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

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

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

的另一个重要特征addEventListener是最后的参数,它控制如何监听到做出反应的事件冒泡 [ DOC ]。我在示例中传递了错误,这对于 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 */ };

除了可以更好地控制范围(因为您正在编写脚本而不是 HTML),并且可以使用匿名函数,函数引用和 / 或闭包之外,... 等效于内联 javascript。

内联事件的显着缺点是,与上述事件侦听器不同,您可能只分配了一个内联事件。内联事件存储为 element [ 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/。

广义上讲,不要使用内联事件。可能有一些特定的用例,但是如果您不是 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 版本中将不起作用。

文档和相关阅读

如果您还有其他几个功能,则可以看到的区别:

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语法稍有不同)。

在这个答案中,我将描述定义 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参数,该参数指示您是要在捕获阶段还是冒泡阶段中处理事件。请参阅: 无法理解 addEventListener 中的 useCapture 属性
  • 关心语义。基本上,它使注册事件处理程序更加明确。对于一个初学者来说,函数调用使得它明显的事情发生,而对 DOM 元素的某些属性分配事件,至少不直观。
  • 允许您分隔文档结构(HTML)和逻辑(JavaScript) 。在小型 Web 应用程序中,这似乎无关紧要,但是对于任何更大的项目而言,它都至关重要。维护一个将结构和逻辑分开的项目要比不保留一个项目的方法容易得多。
  • 消除混淆与正确的事件名称。由于使用内联事件侦听器或将事件侦听器分配给.onevent属性,因此许多没有经验的 JavaScript 程序员都认为事件名称为onclickonloadon不是事件名称的一部分clickload正确的事件名称,这就是将事件名称传递给.addEventListener()
  • 几乎所有浏览器中均可使用。如果仍然必须支持 IE <= 8,则可以使用MDN 中的 polyfill

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 不是 object
  • 没有提供选择要在捕获或冒泡阶段处理事件的方法。

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

代码示例:

<a href="//google.com" onclick="event.preventDefault();">Try clicking this link.</a>

element.onevent相似,现在不建议使用。 element.onevent存在的问题之外,它还具有:

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

也可以看看