这是重读红宝书(JavaScript高级程序设计 第4版)的第5篇文章,本节我们来看看事件:事件流、事件处理程序、事件对象、模拟事件
本节涉及源码见仓库 github.com/adamswan/Re…
1、事件流、事件处理程序/监听器
事件流
DOM2 Events 规范规定事件流分为 3 个阶段:捕获阶段、目标阶段、冒泡阶段
捕获阶段:事件从顶层元素,向下传递,直至目标元素
目标阶段:事件到达目标元素
冒泡阶段:事件从目标元素,向上传递,直至顶层元素
事件处理程序/事件监听器
为响应事件而调用的函数被称为事件处理程序(或事件监听器)
方式1:onxx,它只能添加一个回调
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
.father {
width: 300px;
height: 300px;
background-color: pink;
}
</style>
</head>
<div class="father">
<div class="son"></div>
</div>
<body>
<script>
let father = document.querySelector(".father");
// 用 onclick 只能加一个回调
father.onclick = function () {
console.log("father点击事件1");
};
</script>
</body>
</html>
方式2:addEventListener()
1、它能添加多个回调,多个回调都会被触发,类似观察者模式
2、参数1是事件名、参数2是回调、参数3是布尔值,表示是否 useCapture,默认false,即事件不在捕获阶段触发回调,而是在冒泡阶段触发回调
3、移除事件监听,因为函数地址不同,所以要移除事件时,只能用命令函数或存入变量的匿名函数,否则无法移除事件监听
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
.father {
width: 300px;
height: 300px;
background-color: pink;
}
</style>
</head>
<div class="father">
<div class="son"></div>
</div>
<body>
<script>
let father = document.querySelector(".father");
// 用 addEventListener 可以加多个回调
let clickHandler1 = function () {
console.log("father点击事件2");
};
function clickHandler2() {
console.log("father点击事件3");
}
father.addEventListener("click", clickHandler1);
father.addEventListener("click", clickHandler2);
// 移除第一个事件监听
setTimeout(() => {
father.removeEventListener("click", clickHandler1);
}, 2000);
</script>
</body>
</html>
2、事件对象
事件对象
在 DOM 中发生事件时,所有相关信息都会被收集并存储在一个名为 event 的对象中。这个对象包含了一些基本信息,比如导致事件的元素、发生的事件类型,以及可能与特定事件相关的任何其他数据。
event 上有两个常用方法: preventDefault()、stopPropagation()
preventDefault():
用于阻止特定事件的默认动作,例如取消点击时新开页面
let link = document.getElementById("myLink");
link.onclick = function(event) {
event.preventDefault();
};
stopPropagation():
1、用于立即阻止事件在 DOM 结构中传播,事件捕获、事件冒泡都能阻止
2、一般 addEventListener 的第三个参数为 false ,即默认不使用捕获阶段,所以 stopPropagation 通常阻止的是冒泡,但两个阶段它都能阻止
3、阻止捕获、冒泡的意义:如果父子元素都绑定的点击事件回调,stopPropagation 阻止事件传播后,只允许点击事件触发子元素上的回调
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
.father {
width: 300px;
height: 300px;
background-color: pink;
}
.son {
width: 100px;
height: 100px;
background-color: skyblue;
}
</style>
</head>
<div class="father">
<div class="son"></div>
</div>
<body>
<script>
let father = document.querySelector(".father");
let son = document.querySelector(".son");
father.addEventListener("click", function () {
console.log("father点击事件");
});
son.addEventListener("click", function (e) {
e.stopPropagation();
console.log("son点击事件");
});
</script>
</body>
</html>
3、模拟事件
document.createEvent() 用于创建事件对象,主要用于手动创建自定义事件或模拟浏览器原生事件,然后可以将这些事件分发到指定的 DOM 元素上。
自定义事件
创建自定义的事件类型,用于在应用程序中实现自定义的事件驱动机制,增强代码的可扩展性和灵活性
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
</head>
<body>
<div id="myDiv">这是一个 div 元素</div>
<script>
// 获取 div 元素
const div = document.getElementById("myDiv");
// 为 div 元素添加自定义事件监听器
div.addEventListener("customEvent", function (event) {
console.log("自定义事件被触发了,携带的数据是:", event.detail);
});
// 创建一个自定义事件
const customEvent = document.createEvent("CustomEvent");
// 初始化自定义事件
customEvent.initCustomEvent("customEvent", true, true, {
message: "这是自定义事件携带的数据",
});
// 分发自定义事件到 div 元素上
div.dispatchEvent(customEvent);
</script>
</body>
</html>
模拟用户交互事件
通过创建并分发事件来模拟用户的操作,例如点击、鼠标移动、键盘输入等,常用于自动化测试中
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
</head>
<body>
<button id="myButton">点击我</button>
<script>
// 获取按钮元素
const button = document.getElementById("myButton");
// 为按钮添加点击事件监听器
button.addEventListener("click", function () {
console.log("按钮被点击了!");
});
// 创建一个鼠标事件
const clickEvent = document.createEvent("MouseEvents");
// 初始化鼠标事件
clickEvent.initMouseEvent(
"click",
true,
true,
window,
0,
0,
0,
0,
0,
false,
false,
false,
false,
0,
null
);
// 分发事件到按钮上
button.dispatchEvent(clickEvent);
</script>
</body>
</html>