文章目录
- 13 事件流
- 13.1 事件流
- 13.1.1 事件冒泡
- 13.1.2 事件捕获
- 13.1.3 DOM事件流
- 13.2 事件处理程序
- 某个元素支持的每种事件,都可以使用一个与相应事件处理程序同名的 HTML 特性来指定。这个
- 13.2.2 DOM0 级事件处理程序
- 13.2.3 DOM2 级事件处理程序
- 13.2.4 IE事件处理程序
- 13.2.5 跨浏览器的事件处理程序
- 13.3 事件对象
- 13.3.1 DOM中的事件对象
- 13.3.2 IE中的事件对象
- 13.3.3 跨浏览器的事件对象
13 事件流
javaScript 与 HTML 之间的交互是通过事件实现的。事件,就是文档或浏览器窗口中发生的一些特定的交互瞬间。可以使用侦听器(或处理程序)来预订事件,以便事件发生时执行相应的代码。这种在传统软件工程中被称为观察员模式的模型,支持页面的行为( JavaScript 代码)与页面的外观( HTML 和 CSS 代码)之间的松散耦合.
13.1 事件流
IE 的事件流是事件冒泡流,而 Netscape Communicator 的事件流是事件捕获流。
13.1.1 事件冒泡
IE 的事件流叫做事件冒泡( event bubbling),即事件开始时由最具体的元素(文档中嵌套层次最深
的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档)。以下面的 HTML 页面为例:
如果你单击了页面中的<div>元素,那么这个 click 事件会按照如下顺序传播:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ppgZsDQy-1579591369552)(/images/frontend-JavaScript-event-iecapture.jpg)]
13.1.2 事件捕获
另一种事件流叫做事件捕获( event capturing)。事件捕获的思想是不太具体的节点应该更早接收到事件,而最具体的节点应该最后接收到事件。事件捕获的用意在于在事件到达预定目标之前捕获它。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mt1cFz51-1579591369553)(/iamges/frontend-javascript-event-netscape-capture.jpg)]
13.1.3 DOM事件流
“DOM2级事件”规定的事件流包括三个阶段:事件捕获阶段、处于目标阶段和事件冒泡阶段。首先发生的是事件捕获,为截获事件提供了机会。然后是实际的目标接收到事件。最后一个阶段是冒泡阶段,可以在这个阶段对事件做出响应。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OC6ZGLqR-1579591369554)(/images/frontend-javascript-event-domevent.jpg)]
13.2 事件处理程序
事件就是用户或浏览器自身执行的某种动作。诸如 click、 load 和 mouseover,都是事件的名字。而响应某个事件的函数就叫做事件处理程序(或事件侦听器)。
某个元素支持的每种事件,都可以使用一个与相应事件处理程序同名的 HTML 特性来指定。这个
特性的值应该是能够执行的 JavaScript 代码。例如,要在按钮被单击时执行一些 JavaScript,可以像下面这样编写代码:
当单击这个按钮时,就会显示一个警告框。这个操作是通过指定 onclick 特性并将一些 JavaScript代码作为它的值来定义的。由于这个值是 JavaScript,因此不能在其中使用未经转义的 HTML 语法字符,例如和号( &)、双引号( “”)、小于号( <)或大于号( >)。为了避免使用 HTML 实体,这里使用了单引号。如果想要使用双引号,那么就要将代码改写成如下所示:
在 HTML 中定义的事件处理程序可以包含要执行的具体动作,也可以调用在页面其他地方定义的脚本,如下面的例子所示:
关于这个动态创建的函数,另一个有意思的地方是它扩展作用域的方式。在这个函数内部,可以像访问局部变量一样访问 document 及该元素本身的成员。这个函数使用 with 像下面这样扩展作用域:
如果当前元素是一个表单输入元素,则作用域中还会包含访问表单元素(父元素)的入口,这个函数就变成了如下所示:
这样扩展事件处理程序的作用域链在不同浏览器中会导致不同结果。不同 JavaScript引擎遵循的标识符解析规则略有差异,很可能会在访问非限定对象成员时出错。
通过 HTML 指定事件处理程序的最后一个缺点是 HTML 与 JavaScript 代码紧密耦合。如果要更换事件处理程序,就要改动两个地方: HTML 代码和 JavaScript 代码。
13.2.2 DOM0 级事件处理程序
通过 JavaScript 指定事件处理程序的传统方式,就是将一个函数赋值给一个事件处理程序属性。这种为事件处理程序赋值的方法是在第四代 Web 浏览器中出现的,而且至今仍然为所有现代浏览器所支持。原因一是简单,二是具有跨浏览器的优势。要使用 JavaScript 指定事件处理程序,首先必须取得一个要操作的对象的引用。
13.2.3 DOM2 级事件处理程序
“DOM2 级事件” 定义了两个方法,用于处理指定和删除事件处理程序的操作: addEventListener()和 removeEventListener()。所有 DOM 节点中都包含这两个方法,并且它们都接受 3 个参数:要处理的事件名、作为事件处理程序的函数和一个布尔值。最后这个布尔值参数如果是 true,表示在捕获阶段调用事件处理程序;如果是 false,表示在冒泡阶段调用事件处理程序。
通过 addEventListener()添加的事件处理程序只能使用 removeEventListener()来移除;移除时传入的参数与添加处理程序时使用的参数相同。这也意味着通过 addEventListener()添加的匿名函数将无法移除,如下面的例子所示。
传入 removeEventListener()中的事件处理程序函数必须与传入addEventListener()中的相同
13.2.4 IE事件处理程序
IE 实现了与 DOM 中类似的两个方法: attachEvent()和 detachEvent()。这两个方法接受相同的两个参数:事件处理程序名称与事件处理程序函数。由于 IE8 及更早版本只支持事件冒泡,所以通过attachEvent()添加的事件处理程序都会被添加到冒泡阶段
这里调用了两次 attachEvent(),为同一个按钮添加了两个不同的事件处理程序。不过,与 DOM方法不同的是,这些事件处理程序不是以添加它们的顺序执行,而是以相反的顺序被触发。单击这个例子中的按钮,首先看到的是"Hello world!",然后才是"Clicked"。
使用 attachEvent()添加的事件可以通过 detachEvent()来移除,条件是必须提供相同的参数。与 DOM 方法一样,这也意味着添加的匿名函数将不能被移除。
13.2.5 跨浏览器的事件处理程序
第一个要创建的方法是 addHandler(),它的职责是视情况分别使用 DOM0 级方法、 DOM2 级方法或 IE 方法来添加事件。
与 addHandler()对应的方法是 removeHandler(),它也接受相同的参数。这个方法的职责是移除之前添加的事件处理程序
这两个方法首先都会检测传入的元素中是否存在 DOM2 级方法。如果存在 DOM2 级方法,则使用该方法:传入事件类型、事件处理程序函数和第三个参数 false(表示冒泡阶段)。如果存在的是 IE 的方法,则采取第二种方案。
13.3 事件对象
在触发 DOM 上的某个事件时,会产生一个事件对象 event,这个对象中包含着所有与事件有关的信息。
13.3.1 DOM中的事件对象
兼容 DOM 的浏览器会将一个 event 对象传入到事件处理程序中。无论指定事件处理程序时使用什么方法( DOM0 级或 DOM2 级),都会传入 event 对象。
event 对象包含与创建它的特定事件有关的属性和方法。触发的事件类型不一样,可用的属性和方法也不一样。
属性/方法 | 类 型 | 读/写 | 说 明 |
bubbles | Boolean | 只读 | 表明事件是否冒泡 |
cancelable | Boolean | 只读 | 表明是否可以取消事件的默认行为 |
currentTarget | Element | 只读 | 其事件处理程序当前正在处理事件的那个元素 |
defaultPrevented | Boolean | 只读 | 为true表示已经调用了preventDefault()(DOM3级事件中新增) |
detail | Integer | 只读 | 与事件相关的细节信息 |
eventPhase | Integer | 只读 | 调用事件处理程序的阶段: 1表示捕获阶段, 2表示“处于目标”, 3表示冒泡阶段 |
preventDefault() | Function | 只读 | 取消事件的默认行为 。 如果cancelable是true,则可以使用这个方法 |
stopImmediatePropagation() | Function | 只读 | 取消事件的进一步捕获或冒泡,同时阻止任何事件处理程序被调用( DOM3级事件中新增) |
stopPropagation() | Function | 只读 | 取消事件的进一步捕获或冒泡。如果bubbles为true,则可以使用这个方法 |
target | Element | 只读 | 事件的目标 |
trusted | Boolean | 只读 | 为true表示事件是浏览器生成的。为false表示事件是由开发人员通过JavaScript创建的(DOM3级事件中新增) |
type | String | 只读 | 被触发的事件的类型 |
view | AbstractView | 只读 | 与事件关联的抽象视图。等同于发生事件的window对象 |
在需要通过一个函数处理多个事件时,可以使用 type 属性。例如:
要阻止特定事件的默认行为,可以使用 preventDefault()方法。
只有 cancelable 属性设置为 true 的事件,才可以使用 preventDefault()来取消其默认行为。
另外, stopPropagation()方法用于立即停止事件在 DOM 层次中的传播,即取消进一步的事件捕获或冒泡。
13.3.2 IE中的事件对象
与访问 DOM 中的 event 对象不同,要访问 IE 中的 event 对象有几种不同的方式,取决于指定事件处理程序的方法
通过 window.event 取得了 event 对象,并检测了被触发事件的类型( IE 中的 type属性与 DOM 中的 type 属性是相同的)。事件处理程序是使用 attachEvent()添加的,那么就会有一个 event 对象作为参数被传入事件处理程序函数中.
属性/方法 | 类 型 | 读/写 | 说 明 |
cancelBubble | Boolean | 读/写 | 默认值为false,但将其设置为true就可以取消事件冒泡(与DOM中的stopPropagation()方法的作用相同) |
returnValue | Boolean | 读/写 | 默认值为true,但将其设置为false就可以取消事件的默认行为(与DOM中的preventDefault()方法的作用相同) |
srcElement | Element | 只读 | 事件的目标(与DOM中的target属性相同) |
type | String | 只读 | 被触发的事件的类型 |
使用 event.srcElement 比较保险
returnValue 属性相当于 DOM 中的 preventDefault()方法,它们的作用都是取消给定事件的默认行为。只要将 returnValue 设置为 false,就可以阻止默认行为。
13.3.3 跨浏览器的事件对象
虽然 DOM 和 IE 中的 event 对象不同,但基于它们之间的相似性依旧可以拿出跨浏览器的方案来。IE 中 event 对象的全部信息和方法 DOM 对象中都有,只不过实现方式不一样。
第一个是 getEvent(),它返回对 event对象的引用。
第二个方法是 getTarget(),它返回事件的目标。在这个方法内部,会检测 event 对象的 target属性,如果存在则返回该属性的值;否则,返回 srcElement 属性的值。
第三个方法是 preventDefault(),用于取消事件的默认行为。在传入 event 对象后,这个方法会检查是否存在 preventDefault()方法,如果存在则调用该方法。如果 preventDefault()方法不存在,则将 returnValue 设置为 false。
第四个方法是 stopPropagation(),其实现方式类似。首先尝试使用 DOM 方法阻止事件流,否则就使用 cancelBubble 属性。