学习链接
事件模型-1
监听函数
HTML 的 on- 属性
<body onload="doSomething()">
<div onclick="console.log('触发事件')">
注意,这些属性的值是将会执行的代码,而不是一个函数。
<!-- 正确 -->
<body onload="doSomething()">
<!-- 错误 -->
<body onload="doSomething">
只会在冒泡阶段触发。
元素节点的事件属性
window.onload = doSomething;
div.onclick = function (event) {
console.log('触发事件');
};
属性的值是将一个函数,而不是会执行的代码。
只会在冒泡阶段触发。
EventTarget.addEventListener()
EventTarget.addEventListener()
target.addEventListener(type, listener[, useCapture]);
该方法接受三个参数。
type
:事件名称,大小写敏感。listener
:监听函数。可为具有**handleEvent()**
方法的对象。useCapture
:布尔值,如果设为**true**
,表示监听函数将在捕获阶段(capture)触发。
该参数可选,默认值为**false**
(监听函数只在冒泡阶段被触发)。
如果为同一个事件多次添加同一个监听函数,该函数只会执行一次,多余的添加将自动被去除
(不必使用removeEventListener()
方法手动去除)。
第三个参数不同,会被视为不同的监听函数。
即在一个对象上的不同阶段绑定了同一个监听函数,会被视为不同的监听函数,触发两次。
三者对比
- HTML 的 on- 属性
违反了 HTML 与 JavaScript 代码相分离的原则。 - 元素节点的事件属性
同一个事件只能定义一个监听函数。
也就是说,如果定义两次onclick
属性,后一次定义会覆盖前一次。 - EventTarget.addEventListener() 👍
- 同一事件可添加多个监听函数
- 可指定触发监听函数的阶段(捕获阶段或者冒泡阶段)
事件的传播
一个事件发生后,会在子元素和父元素之间传播(propagation)。这种传播分成三个阶段。
- 第一阶段:从
window
对象传导到目标节点(上层传到底层),称为“捕获阶段”(capture phase)。 - 第二阶段:在目标节点上触发,称为“目标阶段”(target phase)。
- 第三阶段:从目标节点传导回
window
对象(从底层传回上层),称为“冒泡阶段”(bubbling phase)。
事件传播的最上层对象是window
,接着依次是document
,html
(document.documentElement
)和body
(document.body
),逐层到达目标节点。
监听函数的 this
指向
若参数 listener
为普通函数,则 this
指向触发事件的节点。
若参数 listener
为箭头函数,则 this
一般指向 window
。
若参数 listener
为具有 **handleEvent()**
方法的对象,则 this
指向该对象。
Event.currentTarget,Event.target
event.target
:原始触发事件的节点,不会随着事件的传播而改变。event.currentTarget
:绑定事件监听函数的节点,即事件当前所在的节点,会随着事件的传播而改变。
是回调函数为普通函数的 this 指向。
事件的代理 / 委托
由于事件会在冒泡阶段向上传播到父节点,因此可以把子节点的监听函数定义在父节点上,
由父节点的监听函数统一处理多个子元素的事件。这种方法叫做事件的代理(delegation)。
- 节省内存,减少 DOM 操作,提高性能
- 不需要给子节点注销事件
- 动态绑定事件
如果希望事件到某个节点为止,不再传播,可以使用事件对象的stopPropagation
方法。
但是,stopPropagation
方法只会阻止事件的传播,不会阻止该事件触发<p>
节点的其他click
事件的监听函数。也就是说,不是彻底取消该事件的监听。
如果想要彻底取消该事件,不再触发后面所有该事件的监听函数,可以使用stopImmediatePropagation
方法。
特殊事件
所有事件都要经过捕获阶段和处于目标阶段,但有些事件没有冒泡阶段。
**mouseover**
:鼠标经过自身盒子会触发,经过子盒子还会触发。**mouseenter**
:只会经过自身盒子触发。**mouseenter**
和**mouseleave**
无冒泡阶段
**focus**
和**blur**
事件无冒泡阶段