事件处理与事件流
事件机制是浏览器交互的基础,理解事件流模型对前端开发至关重要。
事件流模型
三阶段流程
HTML
捕获阶段 → 目标阶段 → 冒泡阶段
JavaScript
<div id="outer">
<div id="inner">
<button id="btn">点击</button>
</div>
</div>
<script>
// 捕获阶段(从外到内)
document.addEventListener('click', () => console.log('document捕获'), true);
outer.addEventListener('click', () => console.log('outer捕获'), true);
inner.addEventListener('click', () => console.log('inner捕获'), true);
// 冒泡阶段(从内到外)
btn.addEventListener('click', () => console.log('btn冒泡'), false);
inner.addEventListener('click', () => console.log('inner冒泡'), false);
outer.addEventListener('click', () => console.log('outer冒泡'), false);
</script>
addEventListener参数
JavaScript
element.addEventListener(event, handler, useCapture);
// useCapture:
// true - 捕获阶段触发
// false - 冒泡阶段触发(默认)
事件绑定方式
传统方式对比
JavaScript
// DOM0级(无法同时绑定多个)
btn.onclick = function() { };
btn.onclick = null; // 解绑
// DOM2级(推荐)
btn.addEventListener('click', handler);
btn.removeEventListener('click', handler);
| 方式 | 特点 |
|---|---|
onclick | 简单、只能一个处理函数 |
addEventListener | 可绑定多个、支持捕获 |
事件对象
常用属性
JavaScript
btn.addEventListener('click', (e) => {
console.log(e.type); // 'click' 事件类型
console.log(e.target); // 实际触发元素
console.log(e.currentTarget); // 当前绑定元素
console.log(e.clientX); // 鼠标X坐标
console.log(e.clientY); // 鼠标Y坐标
console.log(e.timeStamp); // 时间戳
});
常用方法
JavaScript
btn.addEventListener('click', (e) => {
e.preventDefault(); // 阻止默认行为
e.stopPropagation(); // 阻止事件传播
e.stopImmediatePropagation(); // 阻止后续监听器
});
阻止默认行为
JavaScript
// 阻止链接跳转
document.querySelector('a').addEventListener('click', (e) => {
e.preventDefault();
});
// 阻止表单提交
document.querySelector('form').addEventListener('submit', (e) => {
e.preventDefault();
});
// 阻止右键菜单
document.addEventListener('contextmenu', (e) => {
e.preventDefault();
});
阻止事件传播
HTML
// 阻止冒泡
inner.addEventListener('click', (e) => {
e.stopPropagation();
// 事件不会传播到outer
});
// 阻止捕获和冒泡
inner.addEventListener('click', (e) => {
e.stopImmediatePropagation();
// 后续监听器也不会触发
});
事件委托
基本原理
JavaScript
<ul id="list">
<li>项目1</li>
<li>项目2</li>
<li>项目3</li>
</ul>
<script>
// 委托给父元素
list.addEventListener('click', (e) => {
if (e.target.tagName === 'LI') {
console.log(e.target.textContent);
}
});
// 动态添加元素同样生效
list.innerHTML += '<li>项目4</li>';
</script>
事件委托优势
- 减少内存占用(一个监听器)
- 动态元素自动支持
- 代码更简洁
判断目标元素
JavaScript
list.addEventListener('click', (e) => {
// 精确匹配
if (e.target.tagName === 'LI') { }
// 类选择器匹配
if (e.target.classList.contains('item')) { }
// matches方法匹配
if (e.target.matches('li.item')) { }
// 获取最近匹配元素
const li = e.target.closest('li');
});
常用事件类型
鼠标事件
| 事件 | 触发时机 |
|---|---|
click | 单击 |
dblclick | 双击 |
mouseenter | 鼠标进入(不冒泡) |
mouseleave | 鼠标离开(不冒泡) |
mouseover | 鼠标进入(冒泡) |
mouseout | 鼠标离开(冒泡) |
mousedown | 鼠标按下 |
mouseup | 鼠标释放 |
键盘事件
| 事件 | 触发时机 |
|---|---|
keydown | 按键按下 |
keyup | 按键释放 |
keypress | 按键按下(已废弃) |
text
document.addEventListener('keydown', (e) => {
console.log(e.key); // 'Enter', 'a'
console.log(e.code); // 'Enter', 'KeyA'
console.log(e.keyCode); // 13(已废弃)
});
表单事件
| 事件 | 触发时机 |
|---|---|
submit | 表单提交 |
change | 值改变后失焦触发 |
input | 值改变时触发 |
focus | 获得焦点 |
blur | 失去焦点 |
要点总结
- 事件流:捕获→目标→冒泡三阶段
- addEventListener:推荐使用,支持多个处理函数
- 事件委托:利用冒泡在父元素统一处理
- preventDefault:阻止默认行为
- stopPropagation:阻止事件传播
📝 发现内容有误?点击此处直接编辑