# 事件-Event
Event 接口表示在 DOM 中出现的事件。
一些事件是由用户触发的,例如鼠标或键盘事件;而其他事件常由 API 生成,例如指示动画已经完成运行的事件,视频已被暂停等等。事件也可以通过脚本代码触发,例如对元素调用 HTMLElement.click() 方法,或者定义一些自定义事件,再使用 EventTarget.dispatchEvent() 方法将自定义事件派发往指定的目标(target)。
有许多不同类型的事件,其中一些使用基于 Event 主接口的二次接口。Event 本身包含适用于所有事件的属性和方法。
# 浏览器事件简介
事件 是某事发生的信号。所有的 DOM 节点都生成这样的信号(但事件不仅限于 DOM)。
# 事件处理程序
为了对事件作出响应,我们可以分配一个 处理程序(handler)—— 一个在事件发生时运行的函数。
处理程序是在发生用户行为(action)时运行 JavaScript 代码的一种方式。
<script>
function countRabbits() {
for (let i = 1; i <= 3; i++) {
alert("Rabbit number " + i);
}
}
</script>
<input
type="button"
onclick="countRabbits()"
value="Count rabbits!"
/>
我们知道,HTML 特性名是大小写不敏感的,所以 ONCLICK 和 onClick 以及 onCLICK 都一样可以运行。但是特性通常是小写的:onclick。
我们可以使用 DOM 属性(property)on<event>
来分配处理程序。而不是必须把事件处理程序在 HTML 中进行绑定。
<input type="button" id="button" value="Button" />
<script>
button.onclick = function () {
alert("Click!");
};
</script>
因为这里只有一个 onclick
属性,所以我们无法分配更多事件处理程序。
# 多个处理程序
上述分配处理程序的方式的根本问题是 —— 我们不能为一个事件分配多个处理程序。
假设,在我们点击了一个按钮时,我们代码中的一部分想要高亮显示这个按钮,另一部分则想要显示一条消息。
我们想为此事件分配两个处理程序。但是,新的 DOM 属性将覆盖现有的 DOM 属性:
input.onclick = function () {
alert(1);
};
// ...
input.onclick = function () {
alert(2);
}; // 替换了前一个处理程序
Web 标准的开发者很早就了解到了这一点,并提出了一种使用特殊方法 addEventListener 和 removeEventListener 来管理处理程序的替代方法。它们没有这样的问题。
添加处理程序的语法:
element.addEventListener(event, listener[, options]);
要移除处理程序,可以使用 removeEventListener:
element.removeEventListener(event, listener[, options]);
function handler() {
alert("Thanks!");
}
input.addEventListener("click", handler);
// handler 指向同一个函数
input.removeEventListener("click", handler);
# 事件模型
浏览器的事件模型,就是通过监听函数对事件作出反应。这是事件驱动编程模式的主要编程方式。
# 事件的传播
一个事件发生后会在子元素和父元素之间传播(propagation)。这种传播分成三个阶段。
- 第一阶段:从 window 对象传导到目标节点,称为捕获阶段 capture phase
- 第二阶段:在目标节点上触发,称为目标阶段 target phase
- 第三阶段:从目标阶段传导回 window 对象,称为冒泡阶段。 bubbling phase
这三阶段的传播模型,使得同一事件会在多个节点上触发。
注意浏览器总是假定事件的目标节点,是事件发生位置嵌套最深的那个节点,所以最深的那个节点的捕获和冒泡都会显示为 target 阶段,因此这个节点也会触发两次。
# 事件的代理
由于事件会在冒泡阶段向上传播到父节点,因此可以把子节点的监听函数定义在父节点上,利用 event.target
定位到触发事件的子元素,由父节点的监听函数同意处理多个子元素的事件。这种方法叫做事件的代理(delegation)。
- event.target
var ul = document.querySelector("ul");
ul.addEventListener("click", function (event) {
if (event.target.tagName.toLowerCase() === "li") {
// some code
}
});
如果希望事件到某个节点为止,不在传播,可以使用事件对象的 stopPropagation()方法。这个方法只会阻止事件的传播,不会阻止事件触发节点的其他事件对于的监听函数。
// 事件传播到 p 元素后,就不再向下传播了
p.addEventListener(
"click",
function (event) {
event.stopPropagation();
},
true
);
// 事件冒泡到 p 元素后,就不再向上冒泡了
p.addEventListener(
"click",
function (event) {
event.stopPropagation();
},
false
);
# 事件对象 Event
事件发生以后,会产生一个 Event 事件对象,作为参数传递给监听函数。浏览器原生提供一个 Event 对象,所有的事件都是这个对象(构造函数)的实例,继承了 Event.prototype 原型对象。
Event 对象的实例属性 | |
---|---|
Event.cancelBubble | 返回一个布尔值,如果设为 true,可以阻止事件冒泡 |
Event.currentTarget | 返回事件当前正在通过的节点(捕获,冒泡) |
Event.target | 返回原始触发事件的那个节点 |
Event.type | 返回一个字符串,表示事件类 |
Event.timeStamp | 返回一个毫秒时间戳,表示事件发生的事件,相对于网页加载成功时 |
Event 对象的实例方法 | |
---|---|
Event.preventDefault() | 取消浏览器对当前事件的默认行为,不会阻止其他事件的传播 |
Event.stopPropagation() | 阻止当前事件在 DOM 中继续传播 |