事件是用户或浏览器执行的某种动作。
// 事件是用户与页面交互的方式
// - 点击按钮
// - 提交表单
// - 按下键盘
// - 鼠标移动
// - 页面加载完成
// 事件处理:当事件发生时执行的代码
const button = document.querySelector("button");
button.addEventListener("click", function() {
console.log("按钮被点击");
});
// 1. 事件源:触发事件的元素
const button = document.querySelector("button");
// 2. 事件类型:什么类型的事件
const eventType = "click";
// 3. 事件处理程序:事件发生时执行的函数
function handler(event) {
console.log("点击事件", event);
}
// 绑定事件
button.addEventListener(eventType, handler);
事件流描述了事件在DOM树中的传播顺序。
事件捕获阶段 → 目标阶段 → 事件冒泡阶段
document → html → body → div → body → html → document
(捕获) (目标) (冒泡)
捕获阶段 目标阶段 冒泡阶段
↓ ↓ ↑
┌─────────────────────────────────────────────────────────────┐
│ document │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ html │ │
│ │ ┌─────────────────────────────────────────────────┐ │ │
│ │ │ body │ │ │
│ │ │ ┌───────────────────────────────────────────┐ │ │ │
│ │ │ │ div │ │ │ │
│ │ │ │ (目标元素被点击) │ │ │ │
│ │ │ └───────────────────────────────────────────┘ │ │ │
│ │ └─────────────────────────────────────────────────┘ │ │
│ └───────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
事件从目标元素向上传播到document。
<div id="grandparent">
<div id="parent">
<div id="child">点击我</div>
</div>
</div>
<script>
const grandparent = document.querySelector("#grandparent");
const parent = document.querySelector("#parent");
const child = document.querySelector("#child");
grandparent.addEventListener("click", () => console.log("grandparent"));
parent.addEventListener("click", () => console.log("parent"));
child.addEventListener("click", () => console.log("child"));
// 点击child,输出顺序:
// child → parent → grandparent
</script>
// 事件委托:利用冒泡机制
const list = document.querySelector("ul");
list.addEventListener("click", function(e) {
if (e.target.tagName === "LI") {
console.log("点击了:", e.target.textContent);
}
});
// 不需要给每个li绑定事件
事件从document向下传播到目标元素。
const grandparent = document.querySelector("#grandparent");
const parent = document.querySelector("#parent");
const child = document.querySelector("#child");
// 第三个参数为true,启用捕获
grandparent.addEventListener("click", () => console.log("grandparent"), true);
parent.addEventListener("click", () => console.log("parent"), true);
child.addEventListener("click", () => console.log("child"), true);
// 点击child,输出顺序:
// grandparent → parent → child
const parent = document.querySelector("#parent");
const child = document.querySelector("#child");
parent.addEventListener("click", () => console.log("父-捕获"), true);
parent.addEventListener("click", () => console.log("父-冒泡"), false);
child.addEventListener("click", () => console.log("子"), false);
// 点击child,输出顺序:
// 父-捕获 → 子 → 父-冒泡
绑定事件处理程序的方式。
<!-- 不推荐:HTML与JS混写 -->
<button onclick="console.log('点击')">按钮</button>
<button onclick="handleClick(event)">按钮</button>
<script>
function handleClick(e) {
console.log("点击", e);
}
</script>
const button = document.querySelector("button");
// 赋值方式
button.onclick = function() {
console.log("点击");
};
// 移除事件
button.onclick = null;
// 缺点:只能绑定一个处理程序
const button = document.querySelector("button");
// 添加事件监听器
button.addEventListener("click", function() {
console.log("点击1");
});
button.addEventListener("click", function() {
console.log("点击2");
});
// 可以绑定多个处理程序
// 点击时两个函数都会执行
// 移除事件监听器
function handler() {
console.log("点击");
}
button.addEventListener("click", handler);
button.removeEventListener("click", handler); // 需要同一个函数引用
| 方式 | 多处理程序 | 移除 | 东巴文建议 |
|---|---|---|---|
| HTML属性 | 否 | 难 | 不推荐 |
| DOM0级 | 否 | 简单 | 简单场景 |
| DOM2级 | 是 | 需引用 | 推荐 |
事件对象包含事件的详细信息。
const button = document.querySelector("button");
button.addEventListener("click", function(event) {
// event就是事件对象
console.log(event);
});
// 箭头函数
button.addEventListener("click", (event) => {
console.log(event);
});
button.addEventListener("click", function(e) {
// 事件类型
console.log(e.type); // "click"
// 事件目标
console.log(e.target); // 实际点击的元素
console.log(e.currentTarget); // 绑定事件的元素
// 事件阶段
console.log(e.eventPhase); // 1捕获 2目标 3冒泡
// 时间戳
console.log(e.timeStamp);
// 是否可以冒泡
console.log(e.bubbles);
// 是否可以取消默认行为
console.log(e.cancelable);
});
element.addEventListener("click", function(e) {
// 鼠标位置(相对于视口)
console.log(e.clientX, e.clientY);
// 鼠标位置(相对于页面)
console.log(e.pageX, e.pageY);
// 鼠标位置(相对于目标元素)
console.log(e.offsetX, e.offsetY);
// 鼠标位置(相对于屏幕)
console.log(e.screenX, e.screenY);
// 按键状态
console.log(e.ctrlKey, e.shiftKey, e.altKey, e.metaKey);
// 鼠标按钮
console.log(e.button); // 0左键 1中键 2右键
});
document.addEventListener("keydown", function(e) {
// 按键值
console.log(e.key); // "Enter", "a", "A"
console.log(e.code); // "Enter", "KeyA"
console.log(e.keyCode); // 已废弃
// 按键状态
console.log(e.ctrlKey, e.shiftKey, e.altKey, e.metaKey);
// 示例:检测快捷键
if (e.ctrlKey && e.key === "s") {
e.preventDefault();
console.log("保存");
}
});
const button = document.querySelector("button");
// 普通函数:this指向绑定事件的元素
button.addEventListener("click", function(e) {
console.log(this === e.currentTarget); // true
console.log(this === button); // true
});
// 箭头函数:this继承外层作用域
button.addEventListener("click", (e) => {
console.log(this); // 外层this(可能是window)
console.log(e.currentTarget); // button
});
const button = document.querySelector("button");
// 需要this时用普通函数
button.addEventListener("click", function() {
this.classList.add("clicked");
});
// 不需要this时可以用箭头函数
button.addEventListener("click", (e) => {
e.target.classList.add("clicked");
});
// 或者使用event.currentTarget
button.addEventListener("click", (e) => {
e.currentTarget.classList.add("clicked");
});
掌握了事件基础后,让我们继续学习:
东巴文(db-w.cn) - 让编程学习更简单
🎯 东巴文寄语:事件是JavaScript与用户交互的核心机制,理解事件流、事件冒泡和事件捕获,掌握事件对象的使用,是前端开发的基础。在 db-w.cn,我们帮你深入理解事件机制!