一、Event 对象的核心概念
- 定义:浏览器或Node.js中表示事件状态的对象,包含事件发生时的所有相关信息。
- 作用:在事件处理函数中传递事件细节(如触发元素、鼠标位置、键盘按键等)。
- 分类:
- 浏览器DOM事件:如
click
、keydown
、submit
。
- 自定义事件:通过
Event
/CustomEvent
创建的用户自定义事件。
- Node.js事件:如
fs.readFile
的data
事件、http
服务器的request
事件。
二、浏览器DOM事件对象(重点)
1. 基础属性与方法(高频)
document.addEventListener('click', (event) => {
console.log(event.target);
console.log(event.currentTarget);
console.log(event.type);
console.log(event.clientX);
console.log(event.pageY);
console.log(event.button);
if (event.type === 'keydown') {
console.log(event.key);
console.log(event.keyCode);
console.log(event.ctrlKey);
}
event.preventDefault();
event.stopPropagation();
});
2. 核心属性解析
- 事件目标相关:
target
:实际触发事件的元素(如点击按钮内的图标,target
是图标元素)。
currentTarget
:事件绑定的元素(如给按钮绑定事件,currentTarget
是按钮)。
- 坐标相关:
clientX/clientY
:鼠标相对于浏览器视口的坐标。
pageX/pageY
:鼠标相对于整个文档的坐标(包含滚动偏移)。
screenX/screenY
:鼠标相对于屏幕的坐标。
- 交互状态相关:
shiftKey/ctrlKey/altKey/metaKey
:修饰键是否按下(布尔值)。
button
:鼠标按键编号(常用于区分左右键点击)。
3. 事件控制方法
preventDefault()
:
stopPropagation()
:
- 用途:阻止事件冒泡(如点击子元素时不触发父元素的事件)。
- 示例:
<div id="parent">
<button id="child">点击我</button>
</div>
document.getElementById('parent').addEventListener('click', () => {
console.log('父元素被点击');
});
document.getElementById('child').addEventListener('click', (e) => {
e.stopPropagation();
console.log('子元素被点击');
});
stopImmediatePropagation()
:
- 比
stopPropagation()
更严格,阻止同一元素上后续事件监听器的执行。
三、不同场景的Event对象差异
1. 常见事件类型的特有属性
事件类型 | 特有属性示例 | 用途说明 |
---|
click (鼠标) | button , clientX , clientY | 鼠标按键和位置 |
keydown (键盘) | key , keyCode , charCode | 按键信息 |
submit (表单) | target.elements | 表单所有输入元素 |
mousemove (鼠标移动) | movementX , movementY | 相对于上一次移动的坐标差 |
input (输入) | data , target.value | 输入的内容 |
2. 浏览器与Node.js事件对象的区别
- 浏览器DOM事件:
- 继承自
Event
接口,包含DOM元素相关属性(如target
)。
- 支持事件冒泡和捕获机制。
- Node.js事件:
四、自定义事件(CustomEvent)
1. 创建与分发自定义事件
const myEvent = new CustomEvent('dataLoaded', {
detail: {
data: [1, 2, 3],
timestamp: new Date()
},
bubbles: true,
cancelable: false
});
document.addEventListener('dataLoaded', (event) => {
console.log('接收到自定义事件数据:', event.detail.data);
});
document.dispatchEvent(myEvent);
2. 应用场景
- 组件通信:在不直接耦合的组件间传递数据(如父子组件非嵌套时)。
- 状态通知:数据加载完成、表单验证通过等场景的全局通知。
- 解耦逻辑:将复杂流程拆分为事件驱动的模块(如状态管理库的设计)。
五、事件委托与Event对象优化(面试加分项)
1. 事件委托原理
- 核心思想:将事件监听器绑定到父元素,通过
event.target
判断实际触发的子元素。
- 示例(优化列表项点击事件):
document.querySelectorAll('li').forEach(li => {
li.addEventListener('click', handleClick);
});
const list = document.querySelector('ul');
list.addEventListener('click', (event) => {
if (event.target.tagName === 'LI') {
const id = event.target.dataset.id;
handleClick(id);
}
});
2. Event对象的性能注意点
- 事件对象池:
- 浏览器会复用
Event
对象以减少内存分配(如event
参数在回调中是同一个实例)。
- 避免异步操作中保存
event
对象(可能被后续事件覆盖)。
- 内存泄漏风险:
- 移除事件监听器时,确保使用相同的回调函数(如用箭头函数会导致无法正确移除)。
- 示例(错误写法):
element.addEventListener('click', () => {});
- 正确写法:
const handler = () => {};
element.addEventListener('click', handler);
element.removeEventListener('click', handler);