事件
JavaScript 与 HTML 的交互是通过事件实现的,事件代表文档或浏览器窗口中某个有意义的时刻。 可以使用仅在事件发生时执行的监听器(也叫处理程序)订阅事件。在传统软件工程领域,这个模型叫 “观察者模式”,其能够做到页面行为(在 JavaScript 中定义)与页面展示(在 HTML 和 CSS 中定义)的分离。
事件最早是在 IE3 和 Netscape Navigator 2 中出现的,当时的用意是把某些表单处理工作从服务器转
移到浏览器上来。到了 IE4 和 Netscape Navigator 3 发布的时候,这两家浏览器都提供了类似但又不同的 API,而且持续了好几代。DOM2 开始尝试以符合逻辑的方式来标准化 DOM 事件 API。目前所有现代浏览器都实现了 DOM2 Events 的核心部分。IE8 是最后一个使用专有事件系统的主流浏览器。
浏览器的事件系统非常复杂。即使所有主流浏览器都实现了 DOM2 Events,规范也没有涵盖所有的事件类型。BOM 也支持事件,这些事件与 DOM 事件之间的关系由于长期以来缺乏文档,经常容易被混淆(HTML5 已经致力于明确这些关系)。而 DOM3 新增的事件 API 又让这些问题进一步复杂化了。 根据具体的需求不同,使用事件可能会相对简单,也可能会非常复杂。但无论如何,理解其中的核心概念还是最重要的。
事件流
在第四代 Web 浏览器(IE4 和 Netscape Communicator 4)开始开发时,开发团队碰到了一个有意思的问题:页面哪个部分拥有特定的事件呢?要理解这个问题,可以在一张纸上画几个同心圆。把手指放到圆心上,则手指不仅是在一个圆圈里,而且是在所有的圆圈里。两家浏览器的开发团队都是以同样的方式看待浏览器事件的。当你点击一个按钮时,实际上不光点击了这个按钮,还点击了它的容器以及整个页面。
事件流描述了页面接收事件的顺序。结果非常有意思,IE 和 Netscape 开发团队提出了几乎完全相反的事件流方案。IE 将支持事件冒泡流,而 Netscape Communicator 将支持事件捕获流。
事件冒泡
当一个元素上的事件被触发时,这个事件会首先被该元素处理,然后事件会逐步向上传递给它的父元素,再传递给祖父元素,直到文档的根元素 (document 或 window)。这种从最具体的目标元素逐步向上传播的事件流被称为冒泡(Bubbling)。
<!doctype html>
<html>
<head>
<title>Event Bubbling Example</title>
</head>
<body>
<div id="myDiv">Click Me</div>
</body>
</html>
所有现代浏览器都支持事件冒泡,只是在实现方式上会有一些变化。IE5.5 及早期版本会跳过 <html>
元素(从<body>
直接到 document
)。现代浏览器中的事件会一直冒泡到 window
对象。
事件捕获
在事件捕获(Event Capturing)过程中,事件的处理顺序与冒泡相反。事件首先从文档的根节点(或最外层的父元素)开始,然后逐级向下传播,直到到达最具体的目标元素。
在 JavaScript 中,可以通过设置事件监听器的第三个参数为 true,来使用事件捕获:
document.getElementById('myDiv').addEventListener(
'click',
function () {
console.log('myDiv Clicked');
},
true,
);
DOM 事件流
DOM2 Events 规范规定事件流分为 3 个阶段:事件捕获、到达目标和事件冒泡。事件捕获最先发生, 为提前拦截事件提供了可能。然后,实际的目标元素接收到事件。最后一个阶段是冒泡,最迟要在这个阶段响应事件。仍以前面那个简单的 HTML 为例,点击 myDiv 元素会以如下所示的顺序触发事件。
在 DOM 事件流中,实际的目标(<div>
元素)在捕获阶段不会接收到事件。这是因为捕获阶段从 document 到<html>
再到<body>
就结束了。下一阶段,即会在<div>
元素上触发事件的“到达目标” 阶段,通常在事件处理时被认为是冒泡阶段的一部分(稍后讨论)。然后,冒泡阶段开始,事件反向传播至文档。
大多数支持 DOM 事件流的浏览器实现了一个小小的拓展。虽然 DOM2 Events 规范明确捕获阶段不命中事件目标,但现代浏览器都会在捕获阶段在事件目标上触发事件。最终结果是在事件目标上有两个机会来处理事件。
事件处理程序
事件意味着用户或浏览器执行的某种动作。比如,单击(click)、加载(load)、鼠标悬停 (mouseover)。为响应事件而调用的函数被称为事件处理程序(或事件监听器)。事件处理程序的名字以"on"