JavaScript 事件介绍
文章目录
JavaScript 中的事件,可以理解成浏览器或用户发出的“信号”。当页面上的某个事情发生时(比如点击按钮、按下键盘、页面加载完成),浏览器就会产生一个对应的事件,我们可以通过编写代码来“监听”并响应这些信号,让网页变得可交互。
1. 事件流:捕获与冒泡
当一个元素上的事件被触发时,事件并不会只在该元素上处理,而是沿着 DOM 树传播。这个过程分为三个阶段:
1、捕获阶段:事件从最外层的 window 开始,逐层向下传递,直到到达触发事件的元素。
2、目标阶段:事件到达实际触发的那个元素。
3、冒泡阶段:事件从触发元素开始,逐层向上冒泡,直到 window。
默认情况下,事件处理程序会在冒泡阶段执行,但我们可以选择在捕获阶段就处理它。
<div id="outer">
<div id="inner">点击这里</div>
</div>
const outer = document.getElementById('outer');
const inner = document.getElementById('inner');
// 冒泡阶段(默认)
outer.addEventListener('click', () => console.log('外层冒泡'), false);
inner.addEventListener('click', () => console.log('内层冒泡'), false);
// 捕获阶段
outer.addEventListener('click', () => console.log('外层捕获'), true);
inner.addEventListener('click', () => console.log('内层捕获'), true);
// 点击 inner 后输出顺序:
// 外层捕获 → 内层捕获 → 内层冒泡 → 外层冒泡
2. 绑定事件处理程序
有三种方式为元素绑定事件:
① HTML 行内属性
<button onclick="handleClick()">按钮</button>
缺点:将结构与行为耦合,不利于维护,且作用域链特殊,不推荐使用。
② DOM 属性赋值
const btn = document.querySelector('button');
btn.onclick = function() {
console.log('点击');
};
// 取消绑定
btn.onclick = null;
缺点:同一事件只能绑定一个处理函数,后面的会覆盖前面的。
③ addEventListener (推荐)
btn.addEventListener('click', function(e) {
console.log('第一次绑定');
});
btn.addEventListener('click', function(e) {
console.log('第二次绑定');
});
// 两个都会执行,不会互相覆盖
可以绑定多个处理函数。
可通过第三个参数控制是在捕获阶段还是冒泡阶段执行:
true / { capture: true }:捕获阶段
false / { capture: false }:冒泡阶段(默认)
可以通过 removeEventListener 解绑,但必须传入同一个函数引用。
现代开发中,第三个参数更多使用选项对象:
btn.addEventListener('click', function handler() {console.log('只绑定一次,再捕获阶段触发');},{
once:true, // 只执行一次,自动解绑
passive: true, // 不会调用 preventDefault(),提升滚动性能
capture: false // 是否在捕获阶段触发
});
3. 事件对象
事件处理程序会收到一个自动生成的 event 对象,包含了与该事件相关的所有信息。
element.addEventListener('click', function(event) {
// 常用属性
event.type // 事件类型,如 'click'
event.target // 实际触发事件的元素(最内层)
event.currentTarget // 绑定事件监听器的元素(即 this)
event.clientX // 鼠标相对于视口的 X 坐标
event.clientY // 鼠标相对于视口的 Y 坐标
event.key // 键盘事件中按下的键值
event.keyCode // 已废弃,请使用 key
// 常用方法
event.preventDefault() // 阻止默认行为(如链接跳转、表单提交)
event.stopPropagation() // 阻止事件继续冒泡或捕获
event.stopImmediatePropagation() // 阻止冒泡,并阻止同一元素上的其他监听器执行
});
target 和 currentTarget 的区别很重
target:你真正点击的那个元素(源头)。
currentTarget:绑定了当前处理函数的那个元素(监听器所在)。
4. 事件委托(Event Delegation)
如果有很多子元素需要绑定同一个事件(比如列表项),可以利用冒泡机制,将监听器加在它们的共同父元素上,然后通过 event.target 判断具体是哪个子元素。
优点:
减少内存:只需一个监听器,而不是给每个子元素都绑定。
支持动态元素:后续通过 JS 添加的子元素也能自动拥有该行为。
const list = document.getElementById('list');
list.addEventListener('click', function(e) {
// 判断点击的是否是 li
if (e.target.tagName === 'LI') {
console.log('你点击了:', e.target.textContent);
}
});
使用 matches 方法更灵活:
list.addEventListener('click', function(e) {
if (e.target.matches('.item-class')) {
// 处理
}
});
5. 常见事件类型速览
鼠标事件
click、dblclick
mousedown、mouseup
mousemove
mouseenter、mouseleave(不冒泡)
mouseover、mouseout(会冒泡)
contextmenu(右键菜单)
键盘事件
keydown、keyup(推荐用来检测按键)
keypress(已废弃,不推荐)
表单事件
submit:表单提交时触发,常用于验证。
change:输入框内容改变且失去焦点时,或下拉选项改变时触发。
input:输入框内容实时改变时触发(更适合实时监听)。
focus、blur:元素获得/失去焦点(不冒泡)。
focusin、focusout:获得/失去焦点(会冒泡,可用于委托)。
文档/窗口事件
DOMContentLoaded:HTML 解析完毕,无需等待样式表、图片加载完。
load:页面所有资源(含图片)加载完成。
resize:窗口大小改变。
scroll:滚动事件(可配合 passive 优化性能)。
beforeunload:页面即将卸载,可用来提示用户保存。
触摸事件(移动端)
touchstart、touchmove、touchend
其他
copy、cut、paste:剪贴板事件。
dragstart、dragover、drop 等:拖拽事件。
6. 自定义事件
除了浏览器原生事件,我们还可以自己创建并触发事件:
// 创建一个事件
const myEvent = new CustomEvent('myAction', {
detail: { message: '自定义事件触发了' }
});
// 监听它
document.addEventListener('myAction', function(e) {
console.log(e.detail.message);
});
// 触发
document.dispatchEvent(myEvent);
这在组件间通信或复杂交互中非常实用。
7. 几个重要技巧与注意事项
1、this 的指向:在通过 addEventListener 绑定的普通函数中,this 指向 event.currentTarget(即绑定事件的元素);如果使用箭头函数,this 会保持外层作用域的值。
2、性能优化:对于 scroll、resize、mousemove 等高频事件,应结合节流(throttle) 或防抖(debounce) 处理。
3、passive 选项:在滚动监听中设置 { passive: true } 可以告诉浏览器你不会调用 preventDefault(),从而让滚动更丝滑。
4、解绑事件:记得在适当的时机用 removeEventListener 清理,避免内存泄漏。
更多推荐




所有评论(0)