JavaScript DOM事件
本文最后更新于:8 个月前
DOM内容较多,而且实用性较高,因此从DOM模型中抽离出来,单独成为一篇。本文内容包括:事件接口、事件流模型、Event对象
JavaScript DOM事件
需要了解具体的DOM事件参考:HTML DOM 事件对象 | 菜鸟教程 (runoob.com)
声明:此文大部分内容整理自事件 - 《阮一峰 JavaScript 教程》 - 书栈网 · BookStack,此文只整理了笔者认为核心重要的内容,需要了解更多详细信息,请参考原文
与单纯阅读相比,整理的过程其实是比较耗时间的,那为什么还要花更多的时间去整理呢?目的是为了提高后续再复习时的效率,为了归纳积累出一个逻辑清晰的知识体系。好记性不如烂笔头,再好的记性也没办法记得所有的东西,尤其还是同质化的知识,预期想着如何一次记得多么深刻,不如想想怎么要二次三次复习更加高效。同时整理归纳的过程也是一遍记忆的过程,在文档中归纳的过程也是在脑海中归纳的过程,说到底这也算是一种记忆方法和技巧。
事件的本质是程序各个组成部分之间的一种通信方式,也是异步编程的一种实现
DOM 的事件操作(监听和触发),都定义在EventTarget
接口。所有节点对象都部署了这个接口,其他一些需要事件通信的浏览器内置对象(比如,XMLHttpRequest
、AudioNode
、AudioContext
)也部署了这个接口
该接口主要提供三个实例方法。
addEventListener
:绑定事件的监听函数removeEventListener
:移除事件的监听函数dispatchEvent
:触发事件
一、EventTarget接口
1、addEventListener
参数依次为:
- 事件名称
- 监听函数
- boolean值,触发类型(true-事件捕获or false-事件冒泡)
关于参数,有两个地方需要注意。首先,第二个参数除了监听函数,还可以是一个具有handleEvent
方法的对象。
1 |
|
其次,第三个参数除了布尔值useCapture
,还可以是一个属性配置对象。该对象有以下属性。
capture
:布尔值,表示该事件是否在捕获阶段
触发监听函数once
:布尔值,表示监听函数是否只触发一次,然后就自动移除passive
:布尔值,表示监听函数不会调用事件的preventDefault
方法。如果监听函数调用了,浏览器将忽略这个要求,并在监控台输出一行警告。
如果希望事件监听函数只执行一次,可以打开属性配置对象的once
属性
1 |
|
addEventListener
方法可以为针对当前对象的同一个事件,添加多个不同的监听函数。这些函数按照添加顺序触发,即先添加先触发。如果为同一个事件多次添加同一个监听函数,该函数只会执行一次,多余的添加将自动被去除(不必使用removeEventListener
方法手动去除)。
1 |
|
具体的实践比较请参阅:VSCode: 前端练习/DOM事件模型.html
2、removeEventListener
参数:与addEventListener完全一致
返回值:没有返回值
注意:removeEventListener
方法移除的监听函数,必须是addEventListener
方法添加的那个监听函数,而且必须在同一个元素节点,否则无效。包括第三个参数也必须相同,否则删除无效。
3.dispatchEvent
EventTarget.dispatchEvent
方法在当前节点上触发指定事件,从而触发监听函数的执行。该方法返回一个布尔值,只要有一个监听函数调用了Event.preventDefault()
,则返回值为false
,否则为true
。
dispatchEvent
方法的参数是一个Event
对象的实例
1 |
|
二、事件模型
1、事件的传播
一个事件发生后,会在子元素和父元素之间传播(propagation)。这种传播分成三个阶段。
- 第一阶段:从
window
对象传导到目标节点(上层传到底层),称为“捕获阶段”(capture phase)。 - 第二阶段:在目标节点上触发,称为“目标阶段”(target phase)。
- 第三阶段:从目标节点传导回
window
对象(从底层传回上层),称为“冒泡阶段”(bubbling phase)。
addEventListener方法可以设置节点在某个阶段的监听函数,理论上来说,两个节点最多可以设置4个监听函数(2个在捕获阶段、2个在冒泡阶段,目标阶段在捕获时触发一次,冒泡时触发一次)
2、监听函数的设置
一共有3种方式
- HTML的on-属性,只会在冒泡阶段触发,违反了 HTML 与 JavaScript 代码相分离的原则,不推荐
- 元素节点的事件属性,只会在冒泡阶段触发,同一个事件只能定义一个监听函数,不推荐
- addEventListener,可以设置在冒泡还是捕获阶段触发,推荐的方式
HTML的on-属性
1 |
|
HTML 语言允许在元素的属性中,直接定义某些事件的监听代码,但是这些属性的值必须是执行代码,而不是函数
元素的事件监听属性,都是on
加上事件名,比如onload
就是on + load
,表示load
事件的监听代码
元素的节点属性
1 |
|
它接收到值是函数,而不是执行代码,与上一点不同
addEventListener
1 |
|
3、this的指向
三种方式,监听函数内部的this
指向触发事件的那个元素节点
1 |
|
4、事件代理
把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件,可以减少DOM节点绑定的函数数量,同时便于统一处理,典型的应用如 ul列表 事件的绑定
1 |
|
如果希望事件到某个节点为止,不再传播,可以使用事件对象的stopPropagation
方法。
1 |
|
但是,stopPropagation
方法只会阻止事件的传播,不会阻止该事件触发<p>
节点的其他click
事件的监听函数。
如果想要彻底取消该事件,不再触发后面所有click
的监听函数,可以使用stopImmediatePropagation
方法。
1 |
|
三、Event对象
事件发生以后,会产生一个事件对象,作为参数传给监听函数。浏览器原生提供一个Event
对象,所有的事件都是这个对象的实例
1、Event概述
Event
对象本身就是一个构造函数,可以用来生成新的实例。
1 |
|
- type,字符串,表示事件的名称
- options,对象,表示事件对象的配置,主要有两个属性:
bubbles
:布尔值,可选,默认为false
,表示事件对象是否冒泡cancelable
:布尔值,可选,默认为false
,表示事件是否可以被取消,即能否用Event.preventDefault()
取消这个事件。一旦事件被取消,就好像从来没有发生过,不会触发浏览器对该事件的默认行为。
1 |
|
2、实例属性
Event.eventPhase
返回一个整数常量,表示事件目前所处的阶段。该属性只读。
- 0,事件目前没有发生。
- 1,事件目前处于捕获阶段,即处于从祖先节点向目标节点的传播过程中。
- 2,事件到达目标节点,即
Event.target
属性指向的那个节点。 - 3,事件处于冒泡阶段,即处于从目标节点向祖先节点的反向传播过程中。
Event.cancelable
返回一个布尔值,表示事件是否可以取消。该属性为只读属性。大多数浏览器的原生事件是可以取消的。比如,取消click
事件,点击链接将无效。
当Event.cancelable
属性为true
时,调用Event.preventDefault()
就可以取消这个事件,阻止浏览器对该事件的默认行为。如果事件不能取消,调用Event.preventDefault()
会没有任何效果。
currentTarget & target
- Event.target,事件的原始触发节点,触发事件的节点,不会改变
- Event.currentTarget,事件当前正在通过的节点,当前执行监听函数所在的那个节点,随着事件的传播而改变
前者通常是后者的后代节点。
Event.isTrusted
Event.isTrusted
属性返回一个布尔值,表示该事件是否由真实的用户行为产生。比如,用户点击链接会产生一个click
事件,该事件是用户产生的;Event
构造函数生成的事件,则是脚本产生的。
3、实例方法
preventDefault()
Event.preventDefault
方法取消浏览器对当前事件的默认行为。该方法只是取消事件对当前元素的默认影响,不会阻止事件的传播。如果要阻止传播,可以使用stopPropagation()
或stopImmediatePropagation()
方法
1 |
|
stopPropagation()
阻止事件在 DOM 中继续传播,防止再触发定义在别的节点上的监听函数,但是不包括在当前节点上其他的事件监听函数。
1 |
|
Event.stopImmediatePropagation()
阻止同一个事件的其他监听函数被调用,不管监听函数定义在当前节点还是其他节点。如果同一个节点对于同一个事件指定了多个监听函数,这些函数会根据添加的顺序依次调用。只要其中有一个监听函数调用了Event.stopImmediatePropagation
方法,其他的监听函数就不会再执行了。