文章目录
- 一.事件核心概念
- 二.常见事件类型(按场景分类)
- 1.鼠标事件
- 2.键盘事件
- 3.表单事件
- 4.页面 / 窗口事件
- 5.触摸事件(移动端)
- 三.事件绑定方式(优先级:推荐 ③ > ② > ①)
- 1.行内绑定(原生 HTML,不推荐)
- 2.DOM 属性绑定(简单场景可用)
- 3.addEventListener(推荐,标准方式)
- 四.事件对象(event)核心属性 / 方法
- 五.事件流(捕获 vs 冒泡)
- 六.事件进阶技巧
- 1.事件委托(事件代理)
- 2.防抖(Debounce)
- 3.节流(Throttle)
- 4.自定义事件
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 标签中,耦合度高,不利于维护:
<buttononclick="handleClick()">点击</button><script>functionhandleClick(){alert('点击了按钮');}</script>⚠️ 缺点:无法绑定多个同类型事件、易引发 XSS、代码分离性差.
2.DOM 属性绑定(简单场景可用)
通过元素属性赋值绑定,只能绑定一个处理函数:
constbtn=document.querySelector('button');// 绑定btn.onclick=function(e){console.log('点击事件',e.target);// e:事件对象};// 解绑btn.onclick=null;⚠️ 缺点:覆盖原有事件(重新赋值会替换之前的处理函数).
3.addEventListener(推荐,标准方式)
W3C 标准,支持绑定多个处理函数,可控制事件流阶段:
constbtn=document.querySelector('button');// 绑定:参数(事件类型,处理函数,是否捕获/配置项)consthandler=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 捕获)
<divclass="parent"style="padding:20px;background:#eee;"><buttonclass="child">点击</button></div><script>constparent=document.querySelector('.parent');constchild=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.事件委托(事件代理)
利用事件冒泡,将子元素的事件绑定到父元素,减少事件绑定数量,优化性能(尤其适用于动态生成的元素):
<ulid="list"><li>项1</li><li>项2</li><!-- 动态添加的li也能触发事件 --></ul><script>constlist=document.getElementById('list');// 委托父元素绑定事件list.addEventListener('click',(e)=>{// 过滤目标元素(仅处理li)if(e.target.tagName==='LI'){console.log('点击了li:',e.target.textContent);}});// 动态添加li,无需重新绑定事件constnewLi=document.createElement('li');newLi.textContent='项3';list.appendChild(newLi);</script>✅ 优点:减少事件绑定、支持动态元素、降低内存占用.
2.防抖(Debounce)
解决高频事件(如resize、scroll、input)频繁触发的问题,仅在事件停止触发后执行一次:
运行;// 防抖函数functiondebounce(fn,delay=300){lettimer=null;returnfunction(...args){clearTimeout(timer);timer=setTimeout(()=>{fn.apply(this,args);},delay);};}// 使用:输入框实时搜索constinput=document.querySelector('input');input.addEventListener('input',debounce(function(e){console.log('搜索:',e.target.value);// 停止输入 300ms 后执行},300));3.节流(Throttle)
限制高频事件的执行频率,每隔指定时间仅执行一次:
运行;// 节流函数functionthrottle(fn,interval=500){letlastTime=0;returnfunction(...args){constnow=Date.now();if(now-lastTime>=interval){fn.apply(this,args);lastTime=now;}};}// 使用:滚动加载window.addEventListener('scroll',throttle(function(){console.log('滚动中...');// 每 500ms 执行一次},500));4.自定义事件
手动创建 / 触发事件,适用于组件通信、自定义交互:
// 1. 创建自定义事件constmyEvent=newCustomEvent('custom-click',{detail:{id:123},// 自定义数据bubbles:true,// 允许冒泡cancelable:true// 允许阻止默认行为});// 2. 绑定自定义事件constbtn=document.querySelector('button');btn.addEventListener('custom-click',(e)=>{console.log('自定义事件触发:',e.detail.id);// 输出 123});// 3. 手动触发事件btn.dispatchEvent(myEvent);