HTML 事件属性:
<button onclick="displayDate()">Try it</button>
Run Code Online (Sandbox Code Playgroud)
使用 HTML DOM 分配事件:
<script>
document.getElementById("myBtn").onclick = function(){ displayDate() };
</script>
Run Code Online (Sandbox Code Playgroud)
这两者有什么区别?使用 (Assign Events Using the HTML DOM) 有什么好处?
谢谢
有很大的不同。
在有 DOM 之前,通过 HTML 事件属性设置的事件处理程序是我们进行事件处理的第一种方式。这种设置事件的方式被称为 DOM Level 0(就像在没有标准之前的事实标准)。当这是这样做的方式时(大约 1995 年),这很好,因为我们别无选择。但是,属性值变成事件处理代码的方式是这样处理的:
HTML 元素声明了一个 event 属性,该属性的值是事件发生时应执行的 JavaScript 代码:
<input type="button" onclick="alert('You clicked me!')" value="Click me">Run Code Online (Sandbox Code Playgroud)
请注意, 的值onclick不是函数引用,只是要运行的松散代码。
这实际上是由浏览器通过在全局作用域中创建一个函数来实现的,该函数充当所提供代码的包装器。我们可以在这里看到:
// Output the value of the onclick property.
// Note the value supplied in the HTML
// is wrapped in a function that we didn't create
alert(document.querySelector("input").onclick);Run Code Online (Sandbox Code Playgroud)
<input type="button" onclick="alert('You clicked me!')" value="Click me">Run Code Online (Sandbox Code Playgroud)
由于全局包装函数中属性值的这种自动包装,不直观的事情经常发生如下:
function foo(){
// This function is invoked by clicking the HTML input element
// so, we may reasonably expect that "this" would reference that
// element. But, as you'll see, it doesn't.
alert("You clicked the " + this.nodeName + " element.");
}Run Code Online (Sandbox Code Playgroud)
<input type="button" onclick="foo()" value="Click me">Run Code Online (Sandbox Code Playgroud)
上述报告undefined是因为实际上,this在该上下文中指的window是没有nodeName属性的 Global对象。但是,如果您不知道 Global 包装器(以及您为什么知道),这将非常令人困惑,因为thisDOM 事件处理程序使用的几乎总是引用导致事件触发的 DOM 元素。
当 DOM 级别 1 事件处理规范出现(1998 年)时,也出现了一种配置事件的新方法。我们现在有代表 HTML 元素的对象,每个对象都有映射到元素属性的属性。出于这个原因,许多人(直到今天)仍然相信使用属性或对象属性在很大程度上是一回事。但是,有一些重要的区别(我在我的另一个答案中写过:请参阅答案的后半部分),因为属性用于设置值,这会影响状态,但属性用于覆盖属性和设置状态。
因此,对于 DOM 事件处理,我们将执行以下操作,您将看到,设置事件回调,不是作为要执行的松散代码,而是通过存储对要在事件发生时调用的函数的引用。因为我们提供了该函数,所以它具有我们存储它的 DOM 对象的范围,我们不再需要用 Global 来包装松散的命令。这会导致this绑定按预期工作:
// Just a reference to a function is used with event
// properties. Not "loose" code. And, because the function
// is actually being stored with the DOM element, this binding
// works as expected.
document.querySelector("input").onclick = foo;
function foo(){
// This function is invoked by clicking the HTML input element
// so, we may reasonably expect that "this" would reference that
// element. But, as you'll see, it doesn't.
alert("You clicked the " + this.nodeName + " element.");
}Run Code Online (Sandbox Code Playgroud)
<input type="button" value="Click me">Run Code Online (Sandbox Code Playgroud)
DOM 事件处理的另一个好处是我们将 JavaScript 内容与 HTML 内容分开(即关注点分离)。这是一个好处,但不是变革的驱动力。
现在,在解释了这两种注册事件的机制之间的差异之后,故事还没有完成。DOM 事件属性仍然存在一个问题,因为如果您想设置多个事件处理程序,您没有一种干净的方法来做到这一点,因为您只能在给定的属性中存储一个函数引用。因此,在现代事件处理中,我们使用.addEventListener(),它允许我们使用我们想要的事件注册尽可能多的事件回调,并且我们知道我们注册的回调将按照我们注册它们的顺序调用,从而获得额外的好处。
// Register an event listener:
document.querySelector("input").addEventListener("click", foo1);
// Register more event listeners:
document.querySelector("input").addEventListener("click", foo3);
document.querySelector("input").addEventListener("click", foo2);
function foo1(){ console.log("Hello from foo1"); }
function foo2(){ console.log("Hello from foo2"); }
function foo3(){ console.log("Hello from foo3"); }Run Code Online (Sandbox Code Playgroud)
<input type="button" value="Click me">Run Code Online (Sandbox Code Playgroud)