news 2026/4/18 10:23:52

JavaScript进阶(四):DOM监听

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
JavaScript进阶(四):DOM监听

文章目录

  • 一.事件监听的三种方式(从旧到新,推荐优先级排序)
    • 1.行内监听(HTML 内联属性,不推荐)
    • 2.DOM 属性监听(元素属性赋值,简单场景可用)
    • 3.addEventListener(标准监听方式,强烈推荐)
  • 二.事件监听的核心概念
    • 1.事件流与监听阶段
    • 2.事件对象(event)的核心作用
  • 三.事件监听的进阶技巧
    • 1.事件委托(代理)
    • 2.高频事件的优化:防抖与节流
      • I.防抖(Debounce)
      • II.节流(Throttle)
    • 3.自定义事件监听
  • 四.事件监听的性能优化
  • 五.常见问题与解决方案
    • 1.匿名函数无法解绑
    • 2.this 指向问题
    • 3.focus/blur 事件不冒泡
    • 4.事件委托中目标元素判断错误
  • 六.总结

DOM事件监听全面详解
事件监听(Event Listener)是DOM交互的核心机制,指为元素注册事件处理函数,当指定事件触发时自动执行该函数.它实现了「行为与结构分离」,是前端处理用户交互、页面状态变化的基础.以下从监听方式、核心配置、进阶技巧、性能优化、常见问题等维度系统拆解.

一.事件监听的三种方式(从旧到新,推荐优先级排序)

1.行内监听(HTML 内联属性,不推荐)

直接在HTML标签中通过on+事件名属性绑定处理函数,是最原始的方式.

语法:

<elementon[事件名]="处理函数(参数)"></element>

示例:

<buttononclick="handleClick('按钮1')">点击我</button><script>functionhandleClick(name){alert(`你点击了${name}`);}</script>

缺点:

  • 耦合度高:HTML结构与JS逻辑混杂,不利于维护;
  • 安全风险: 若拼接用户输入,易引发XSS攻击;
  • 功能有限: 无法绑定多个同类型事件,也无法控制事件流阶段.

2.DOM 属性监听(元素属性赋值,简单场景可用)

通过给DOM元素的on+事件名属性赋值函数,实现事件绑定.

语法:

元素.on[事件名]=处理函数;

示例:

constbtn=document.querySelector('button');// 绑定监听btn.onclick=function(e){console.log('点击事件触发',e.target);};// 解绑监听(赋值为 null 即可)btn.onclick=null;

特点:

  • 优点: 语法简单,兼容性好(支持所有浏览器);
  • 缺点: 只能绑定一个处理函数,重新赋值会覆盖原有函数.

3.addEventListener(标准监听方式,强烈推荐)

W3C制定的标准事件监听API,是现代前端最常用的方式,支持多函数绑定、事件流控制、精细配置.

核心语法:

// 绑定监听元素.addEventListener(事件类型,处理函数,捕获/配置项);// 解绑监听元素.removeEventListener(事件类型,处理函数,捕获/配置项);

关键参数说明:

参数类型说明
事件类型字符串事件名称(如clickinput,不带on前缀)
处理函数函数事件触发时执行的回调(接收事件对象event作为参数)
捕获 / 配置项布尔值 / 对象可选,默认false(冒泡阶段触发);传对象可配置更多选项

基础示例:

constbtn=document.querySelector('button');// 定义处理函数(需命名,方便解绑)constclickHandler=function(e){console.log('点击事件触发',e);};// 绑定监听(冒泡阶段)btn.addEventListener('click',clickHandler);// 绑定多个同类型事件(依次执行)btn.addEventListener('click',()=>{console.log('第二个点击处理函数');});// 解绑监听(必须传同一个函数引用,匿名函数无法解绑)btn.removeEventListener('click',clickHandler);

高级配置项(第三个参数传对象):

btn.addEventListener('scroll',handleScroll,{capture:false,// 是否在**捕获阶段**触发(默认 false,冒泡阶段)once:true,// 事件仅触发一次,触发后自动解绑passive:true,// 禁止处理函数中调用 e.preventDefault()(优化移动端滚动性能)signal:AbortSignal// 通过 AbortController 批量解绑事件(ES2021+)});

signal 配置示例(批量解绑):

constcontroller=newAbortController();const{signal}=controller;// 绑定多个事件,共用同一个 signalbtn.addEventListener('click',()=>console.log('点击 1'),{signal});btn.addEventListener('click',()=>console.log('点击 2'),{signal});// 批量解绑所有绑定的事件controller.abort();

优点:

  1. 支持为同一元素的同一事件绑定多个处理函数;
  2. 可控制事件在捕获 / 冒泡阶段触发;
  3. 提供丰富的配置项(如一次性事件、被动监听);
  4. 支持批量解绑(通过AbortController).

二.事件监听的核心概念

1.事件流与监听阶段

事件在DOM树中传播分为捕获阶段、目标阶段、冒泡阶段,addEventListener的第三个参数决定监听函数在哪个阶段触发:
捕获阶段(capture: true):事件从 window 向下传播到目标元素时触发;
冒泡阶段(capture: false,默认):事件从目标元素向上传播到 window 时触发.
示例:

<divclass="parent"><buttonclass="child">点击</button></div><script>constparent=document.querySelector('.parent');constchild=document.querySelector('.child');// 捕获阶段监听parent.addEventListener('click',()=>console.log('父元素-捕获'),true);// 冒泡阶段监听parent.addEventListener('click',()=>console.log('父元素-冒泡'));child.addEventListener('click',()=>console.log('子元素'));// 点击按钮,执行顺序:父元素-捕获 → 子元素 → 父元素-冒泡</script>

2.事件对象(event)的核心作用

监听函数的第一个参数是事件对象,包含事件的所有关键信息,常用属性 / 方法:

成员作用
e.target事件实际触发的元素(事件源)
e.currentTarget绑定事件的元素(等价于 this)
e.preventDefault()阻止事件的默认行为(如链接跳转、表单提交)
e.stopPropagation()阻止事件继续传播(捕获 / 冒泡)
e.stopImmediatePropagation()阻止事件传播,且同一元素的后续监听函数不再执行

三.事件监听的进阶技巧

1.事件委托(代理)

利用事件冒泡,将子元素的事件监听绑定到父元素,实现「一次绑定,多元素生效」,尤其适用于动态生成的元素.

核心原理:
父元素监听事件后,通过e.target判断触发事件的子元素,执行对应逻辑.

示例(列表项点击监听):

<ulid="list"><li>项1</li><li>项2</li></ul><script>const list = document.getElementById('list'); // 委托父元素绑定点击监听 list.addEventListener('click', (e) => { // 过滤目标元素(仅处理 li 标签) if (e.target.tagName === 'LI') { console.log('点击了列表项:', e.target.textContent); } }); // 动态添加 li,无需重新绑定监听 const newLi = document.createElement('li'); newLi.textContent = '项3'; list.appendChild(newLi);

优点:

  • 减少事件监听的数量,降低内存占用;
  • 支持动态生成的元素,无需重复绑定;
  • 简化代码维护.

2.高频事件的优化:防抖与节流

对于resizescrollinputmousemove等高频触发的事件,直接监听会导致函数频繁执行,引发性能问题,需通过防抖(Debounce) 和节流(Throttle) 优化.

I.防抖(Debounce)

原理:
事件停止触发后,延迟一定时间再执行函数,若期间再次触发则重置延迟.

适用场景:
输入框实时搜索、窗口大小调整.

// 防抖函数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);},300));

II.节流(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('滚动中...');},500));

3.自定义事件监听

除了浏览器内置事件,还可以创建自定义事件,通过dispatchEvent手动触发,适用于组件通信、自定义交互.

示例:

constbtn=document.querySelector('button');// 1. 创建自定义事件(可携带自定义数据)constmyEvent=newCustomEvent('custom-click',{detail:{id:123},// 自定义数据bubbles:true// 允许冒泡});// 2. 绑定自定义事件监听btn.addEventListener('custom-click',(e)=>{console.log('自定义事件触发:',e.detail.id);});// 3. 手动触发自定义事件btn.dispatchEvent(myEvent);

四.事件监听的性能优化

  1. 减少不必要的监听:仅为需要交互的元素绑定监听,避免无意义的监听;
  2. 及时解绑监听:
    • 元素销毁时(如组件卸载),通过removeEventListener解绑监听,避免内存泄漏;
    • 一次性事件使用once: true配置,自动解绑;
  3. 使用事件委托:替代逐个元素绑定,减少监听数量;
  4. 优化高频事件:防抖 / 节流降低函数执行频率;
  5. 移动端优化:
    • 触摸事件(touchstart/touchmove)添加passive: true,提升滚动流畅度;
    • 避免使用click(有 300ms 延迟),可用touchend替代;
  6. 批量解绑:通过AbortController批量管理多个监听,简化解绑逻辑.

五.常见问题与解决方案

1.匿名函数无法解绑

问题:
使用匿名函数绑定的监听,无法通过removeEventListener解绑.

解决:
使用命名函数或保存函数引用.

// 错误:匿名函数无法解绑btn.addEventListener('click',()=>console.log('点击'));btn.removeEventListener('click',()=>console.log('点击'));// 无效// 正确:命名函数consthandler=()=>console.log('点击');btn.addEventListener('click',handler);btn.removeEventListener('click',handler);// 有效

2.this 指向问题

问题:
箭头函数作为监听函数时,this不指向绑定元素(指向外层作用域).

解决:
普通函数的this指向绑定元素,或用e.currentTarget获取.

btn.addEventListener('click',function(){console.log(this);// 指向 btn 元素});btn.addEventListener('click',(e)=>{console.log(e.currentTarget);// 指向 btn 元素(替代 this)});

3.focus/blur 事件不冒泡

问题:
focus/blur事件不支持冒泡,无法使用事件委托.

解决:
使用focusin/focusout 事件(支持冒泡)替代.

// 替代 focusparent.addEventListener('focusin',(e)=>{if(e.target.tagName==='INPUT'){console.log('输入框获取焦点');}});

4.事件委托中目标元素判断错误

问题:
子元素包含嵌套标签时,e.target 可能指向子标签而非目标元素.

解决:
通过向上遍历找到目标元素.

list.addEventListener('click',(e)=>{lettarget=e.target;// 向上遍历,找到 li 元素while(target&&target.tagName!=='LI'){target=target.parentNode;}if(target){console.log('点击了 li:',target.textContent);}});

六.总结

事件监听是前端交互的核心,addEventListener是最推荐的方式,其灵活性和功能性远胜其他方式.掌握事件委托、防抖节流、自定义事件等技巧,能有效提升代码的性能和可维护性.同时,注意及时解绑监听、优化高频事件,可避免内存泄漏和性能问题.

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 6:37:27

Spring Boot整合Activiti的项目中实现抄送功能

目录 1、实现思路 2、在Spring Boot中集成Activiti 2.1、设计抄送表 2.2、抄送实体类 2.3、实现抄送服务 3、前端集成 3.1、抄送组件 3.2、抄送列表页面 4、高级功能扩展 4.1、邮件通知集成 4.2、消息推送集成&#xff08;WebSocket&#xff09; 4.3、 抄送规则配置…

作者头像 李华
网站建设 2026/4/18 6:33:35

GitHub加速终极方案:3分钟告别访问卡顿

GitHub加速终极方案&#xff1a;3分钟告别访问卡顿 【免费下载链接】github-hosts &#x1f525;&#x1f525;&#x1f525; 本项目定时更新GitHub最新hosts&#xff0c;解决GitHub图片无法显示&#xff0c;加速GitHub网页浏览。 项目地址: https://gitcode.com/gh_mirrors/…

作者头像 李华
网站建设 2026/4/18 7:34:49

开源项目构建与发布的5个关键阶段:OBS Studio深度实践指南

开源项目构建与发布的5个关键阶段&#xff1a;OBS Studio深度实践指南 【免费下载链接】obs-studio OBS Studio - 用于直播和屏幕录制的免费开源软件。 项目地址: https://gitcode.com/GitHub_Trending/ob/obs-studio OBS Studio作为直播和屏幕录制领域的标杆开源软件&a…

作者头像 李华
网站建设 2026/4/18 6:47:46

异常行为检测_Cascade_Mask_RCNN_r50_rsb_pre_FPN_1x_Coco训练

1. &#x1f31f; 超全YOLO系列模型大盘点 &#x1f680; 嗨&#xff0c;各位CV小伙伴&#xff01;今天来给大家唠唠计算机视觉领域最火的YOLO系列模型~ 从YOLOv1到最新的YOLOv13&#xff0c;还有各种魔改变种&#xff0c;简直让人眼花缭乱&#xff01;&#x1f631; 这篇文章…

作者头像 李华
网站建设 2026/4/18 7:58:34

YOLOv8改进实战:基于StarNet的水果品质检测与分级系统(附完整代码)

1. YOLOv8改进实战&#xff1a;基于StarNet的水果品质检测与分级系统&#xff08;附完整代码&#xff09; 1.1. 摘要 本文介绍了一个基于改进YOLOv8的水果品质检测与分级系统&#xff0c;通过引入StarNet注意力机制显著提升了模型对小尺寸水果缺陷的检测能力。系统实现了从图…

作者头像 李华
网站建设 2026/4/18 7:58:47

Adobe Source Sans 3 开源字体:从入门到精通的5个实用技巧

Adobe Source Sans 3 开源字体&#xff1a;从入门到精通的5个实用技巧 【免费下载链接】source-sans Sans serif font family for user interface environments 项目地址: https://gitcode.com/gh_mirrors/so/source-sans Adobe Source Sans 3是一款专为现代数字界面设计…

作者头像 李华