想象一个餐厅的点餐系统
可以把 JavaScript 的事件模型想象成一个餐厅的运作方式:
- 顾客(事件):就像各种事件(点击、滚动、键盘输入等)
- 服务员(事件监听器):负责接收并处理顾客的请求
- 点餐单(事件队列):所有顾客的请求都按顺序排在这里等待处理
- 厨师(JavaScript 引擎):一次只能做一个菜(单线程),按顺序处理点餐单
事件模型的三个阶段
1. 捕获阶段(从上往下)
就像餐厅经理先听到顾客喊服务员(从窗户到餐桌):
事件从最外层(window)向内传递到目标元素
很少使用,就像经理一般不直接处理点餐
2. 目标阶段
服务员到达餐桌:
事件到达实际被点击的元素
这是我们最常处理的阶段
3. 目标阶段
冒泡阶段(从下往上)
服务员把订单报给厨师:
事件从目标元素向外传递到最外层
默认情况下事件监听器在这个阶段触发
// 就像三个不同级别的员工
document.querySelector('.爷爷').addEventListener('click', () => {
console.log('经理知道了'); // 捕获阶段
}, true); // true 表示在捕获阶段监听
document.querySelector('.爸爸').addEventListener('click', () => {
console.log('领班处理中'); // 冒泡阶段(默认)
});
document.querySelector('.儿子').addEventListener('click', () => {
console.log('服务员接待'); // 目标阶段
});
事件委托:聪明的经理
利用冒泡机制,把事件处理交给上级元素:
// 不用给每个按钮都安排服务员
document.querySelector('.按钮容器').addEventListener('click', (event) => {
if(event.target.classList.contains('按钮')) {
console.log('你点击了:', event.target.textContent);
}
});
优点:
节省内存(减少事件监听器)
动态元素也能响应(新加的按钮自动有效)
常见事件类型
鼠标事件:click(点击)、mouseover(悬停)
键盘事件:keydown(按键按下)、keyup(按键松开)
表单事件:submit(提交)、change(内容改变)
页面事件:load(加载完成)、scroll(滚动)
实际应用技巧
阻止冒泡:event.stopPropagation()(不让经理知道)
阻止默认行为:event.preventDefault()(不让链接跳转)
一次性事件:{ once: true }(只处理第一次点击)
document.querySelector('a').addEventListener('click', (event) => {
event.preventDefault(); // 阻止链接跳转
console.log('点击了但不会跳转');
});
document.querySelector('button').addEventListener('click', (event) => {
event.stopPropagation(); // 阻止事件冒泡
console.log('只有我会响应');
}, { once: true }); // 只生效一次