文章目录
- 一.事件核心概念
- 二.常见事件类型(按场景分类)
-
- 1.鼠标事件
- 2.键盘事件
- 3.表单事件
- [4.页面 / 窗口事件](#4.页面 / 窗口事件)
- 5.触摸事件(移动端)
- [三.事件绑定方式(优先级:推荐 ③ > ② > ①)](#三.事件绑定方式(优先级:推荐 ③ > ② > ①))
-
- [1.行内绑定(原生 HTML,不推荐)](#1.行内绑定(原生 HTML,不推荐))
- [2.DOM 属性绑定(简单场景可用)](#2.DOM 属性绑定(简单场景可用))
- 3.addEventListener(推荐,标准方式)
- [四.事件对象(event)核心属性 / 方法](#四.事件对象(event)核心属性 / 方法)
- [五.事件流(捕获 vs 冒泡)](#五.事件流(捕获 vs 冒泡))
- 六.事件进阶技巧
DOM 事件是前端交互的核心,指浏览器或用户触发的各类行为(如 点击、滚动、输入 ),通过「事件绑定 - 事件触发 - 事件处理」的流程实现页面交互逻辑.
一.事件核心概念
| 概念 | 说明 |
|---|---|
事件源(target) |
触发事件的 DOM 元素(如点击的按钮、输入的输入框) |
事件类型(type) |
事件的类别(如 click、input、scroll) |
事件处理函数(handler) |
事件触发后执行的函数(也称回调函数) |
事件对象(event) |
事件触发时自动传入处理函数的参数,包含事件的所有信息(如坐标、触发源、按键) |
| 事件流 | 事件在 DOM 树中的传播过程(捕获阶段 → 目标阶段 → 冒泡阶段) |
二.常见事件类型(按场景分类)
1.鼠标事件
最常用的交互事件,适用于点击、悬浮、拖拽等场景:
| 事件名 | 触发时机 | 常用场景 |
|---|---|---|
click |
鼠标左键单击(按下 + 松开) | 按钮点击、链接跳转 |
dblclick |
鼠标左键双击 | 双击编辑、双击放大 |
mousedown |
鼠标按键按下(任意键) | 拖拽开始、按住操作 |
mouseup |
鼠标按键松开(任意键) | 拖拽结束、释放操作 |
mousemove |
鼠标在元素内移动 | 拖拽跟随、鼠标轨迹 |
mouseover |
鼠标移入元素(含子元素,会冒泡) | 悬浮提示(慎用,推荐 mouseenter) |
mouseenter |
鼠标移入元素(不含子元素,不冒泡) | 悬浮菜单、卡片高亮 |
mouseout |
鼠标移出元素(含子元素,会冒泡) | 悬浮提示消失 |
mouseleave |
鼠标移出元素(不含子元素,不冒泡) | 悬浮菜单收起 |
contextmenu |
鼠标右键单击 | 自定义右键菜单 |
2.键盘事件
适用于键盘操作(输入、快捷键):
| 事件名 | 触发时机 | 关键属性(event) |
|---|---|---|
keydown |
键盘按键按下(持续按会重复触发) | key(按键名,如 Enter)、 code(按键编码)、 ctrlKey/shiftKey(修饰键) |
keyup |
键盘按键松开 | 同上 |
keypress |
按键按下且产生字符(已废弃,用 keydown 替代) |
- |
3.表单事件
适用于表单元素交互:
| 事件名 | 触发时机 | 适用元素 |
|---|---|---|
input |
表单值变化(实时触发) | input / textarea / select |
change |
表单值变化且失去焦点(或下拉框选中) | 同上 |
focus |
元素获取焦点(不冒泡) | 所有表单元素、可聚焦元素(如 div 加 tabindex) |
blur |
元素失去焦点(不冒泡) | 同上 |
submit |
表单提交(点击提交按钮 / 按 Enter) |
form 元素 |
reset |
表单重置 | form 元素 |
4.页面 / 窗口事件
适用于页面加载、尺寸变化、滚动等:
| 事件名 | 触发时机 | 注意事项 |
|---|---|---|
load |
页面 / 资源(img/script)加载完成 |
window.onload:页面所有资源加载完成;img.onload:单张图片加载完成 |
DOMContentLoaded |
DOM 解析完成(无需等待资源加载) |
比 load 早触发,优先用于初始化逻辑 |
resize |
窗口 / 元素尺寸变化 | 高频事件,需防抖 |
scroll |
页面 / 元素滚动 | 高频事件,需防抖 / 节流 |
unload |
页面卸载(关闭 / 跳转) | 慎用,执行时机不可靠,推荐 beforeunload |
beforeunload |
页面即将卸载 | 可提示用户 "是否离开" |
5.触摸事件(移动端)
适用于手机 / 平板的触摸操作:
| 事件名 | 触发时机 | 关键属性(event) |
|---|---|---|
touchstart |
手指触摸屏幕 | touches(所有触摸点)、 targetTouches(当前元素触摸点) |
touchmove |
手指在屏幕上滑动 | 同上,可获取滑动坐标 |
touchend |
手指离开屏幕 | 同上 |
touchcancel |
触摸被中断(如弹窗、电话) | - |
三.事件绑定方式(优先级:推荐 ③ > ② > ①)
1.行内绑定(原生 HTML,不推荐)
直接写在 HTML 标签中,耦合度高,不利于维护:
html
<button onclick="handleClick()">点击</button>
<script>
function handleClick() {
alert('点击了按钮');
}
</script>
⚠️ 缺点:无法绑定多个同类型事件、易引发 XSS、代码分离性差.
2.DOM 属性绑定(简单场景可用)
通过元素属性赋值绑定,只能绑定一个处理函数:
javascript
const btn = document.querySelector('button');
// 绑定
btn.onclick = function (e) {
console.log('点击事件', e.target); // e:事件对象
};
// 解绑
btn.onclick = null;
⚠️ 缺点:覆盖原有事件(重新赋值会替换之前的处理函数).
3.addEventListener(推荐,标准方式)
W3C 标准,支持绑定多个处理函数,可控制事件流阶段:
javascript
const btn = document.querySelector('button');
// 绑定:参数(事件类型,处理函数,是否捕获/配置项)
const handler = function (e) {
console.log('点击事件', e);
};
btn.addEventListener('click', handler);
// 绑定多个同类型事件(依次执行)
btn.addEventListener('click', () => {
console.log('第二个点击处理函数');
});
// 解绑:必须传绑定的同一个函数(匿名函数无法解绑)
btn.removeEventListener('click', handler);
// 配置项(第三个参数可传对象,替代布尔值)
btn.addEventListener('scroll', handleScroll, {
capture: false, // 否在捕获阶段触发(默认 false,冒泡阶段)
once: true, // 事件仅触发一次(自动解绑)
passive: true // 禁止阻止默认行为(优化移动端滚动性能)
});
✅ 优点:支持多函数绑定、精准解绑、控制事件流、丰富配置项.
四.事件对象(event)核心属性 / 方法
事件处理函数的第一个参数是事件对象,包含事件的所有关键信息:
| 属性 / 方法 | 作用 | 示例 |
|---|---|---|
target |
事件实际触发的元素(事件源) | e.target(冒泡时不会变) |
currentTarget |
绑定事件的元素(this 等价) |
e.currentTarget(冒泡时指向当前处理的元素) |
type |
事件类型(如 click、input) |
e.type // "click" |
clientX / clientY |
鼠标相对于视口的坐标(不含滚动) | 鼠标点击位置:e.clientX + 'px' |
pageX / pageY |
鼠标相对于文档的坐标(含滚动) | - |
key |
键盘事件的按键名(如 Enter、a) |
if (e.key === 'Enter') { 提交表单 } |
ctrlKey / shiftKey / altKey |
是否按下修饰键(布尔值) | if (e.ctrlKey && e.key === 's') { 保存 } |
preventDefault() |
阻止事件默认行为 | 阻止链接跳转:e.preventDefault() |
stopPropagation() |
阻止事件冒泡 / 捕获 | 阻止父元素触发同类型事件 |
stopImmediatePropagation() |
阻止事件传播 + 同元素后续处理函数 | 绑定多个 click 函数时,后续函数不执行 |
bubbles |
事件是否可冒泡(布尔值) | e.bubbles // true(如 click 可冒泡,focus 不可) |
五.事件流(捕获 vs 冒泡)
事件触发后,会在 DOM 树中经历三个阶段(W3C 标准):
- 捕获阶段:从
window→ 文档 → 父元素 → 目标元素(从上到下); - 目标阶段:事件到达实际触发的元素;
- 冒泡阶段:从目标元素 → 父元素 → 文档 →
window(从下到上).
核心示例(冒泡 vs 捕获)
html
<div class="parent" style="padding: 20px; background: #eee;">
<button class="child">点击</button>
</div>
<script>
const parent = document.querySelector('.parent');
const child = document.querySelector('.child');
// 冒泡阶段触发(默认)
parent.addEventListener('click', () => console.log('父元素-冒泡'));
child.addEventListener('click', () => console.log('子元素-冒泡'));
// 捕获阶段触发(第三个参数为true)
parent.addEventListener('click', () => console.log('父元素-捕获'), true);
child.addEventListener('click', () => console.log('子元素-捕获'), true);
// 点击按钮,执行顺序:
// 父元素-捕获 → 子元素-冒泡 → 子元素-捕获 → 父元素-冒泡
// (目标阶段不分捕获/冒泡,按绑定顺序执行)
</script>
六.事件进阶技巧
1.事件委托(事件代理)
利用事件冒泡,将子元素的事件绑定到父元素,减少事件绑定数量,优化性能(尤其适用于动态生成的元素):
html
<ul id="list">
<li>项1</li>
<li>项2</li>
<!-- 动态添加的li也能触发事件 -->
</ul>
<script>
const list = document.getElementById('list');
// 委托父元素绑定事件
list.addEventListener('click', (e) => {
// 过滤目标元素(仅处理li)
if (e.target.tagName === 'LI') {
console.log('点击了li:', e.target.textContent);
}
});
// 动态添加li,无需重新绑定事件
const newLi = document.createElement('li');
newLi.textContent = '项3';
list.appendChild(newLi);
</script>
✅ 优点:减少事件绑定、支持动态元素、降低内存占用.
2.防抖(Debounce)
解决高频事件(如 resize、scroll、input)频繁触发的问题,仅在事件停止触发后执行一次:
javascript
运行;
// 防抖函数
function debounce(fn, delay = 300) {
let timer = null;
return function (...args) {
clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this, args);
}, delay);
};
}
// 使用:输入框实时搜索
const input = document.querySelector('input');
input.addEventListener(
'input',
debounce(function (e) {
console.log('搜索:', e.target.value); // 停止输入 300ms 后执行
}, 300)
);
3.节流(Throttle)
限制高频事件的执行频率,每隔指定时间仅执行一次:
javascript
运行;
// 节流函数
function throttle(fn, interval = 500) {
let lastTime = 0;
return function (...args) {
const now = Date.now();
if (now - lastTime >= interval) {
fn.apply(this, args);
lastTime = now;
}
};
}
// 使用:滚动加载
window.addEventListener(
'scroll',
throttle(function () {
console.log('滚动中...'); // 每 500ms 执行一次
}, 500)
);
4.自定义事件
手动创建 / 触发事件,适用于组件通信、自定义交互:
javascript
// 1. 创建自定义事件
const myEvent = new CustomEvent('custom-click', {
detail: { id: 123 }, // 自定义数据
bubbles: true, // 允许冒泡
cancelable: true // 允许阻止默认行为
});
// 2. 绑定自定义事件
const btn = document.querySelector('button');
btn.addEventListener('custom-click', (e) => {
console.log('自定义事件触发:', e.detail.id); // 输出 123
});
// 3. 手动触发事件
btn.dispatchEvent(myEvent);