当前位置: 首页 > article >正文

JavaScript 中的事件委托机制,它有什么优点和适用场景?

大白话JavaScript 中的事件委托机制,它有什么优点和适用场景?

什么是事件委托机制

在 JavaScript 里,事件委托是一种很实用的技术。简单来说,就是把事件处理程序绑定到一个父元素上,而不是直接绑定到每个子元素。当子元素上触发了对应的事件时,这个事件会冒泡到父元素上,父元素上绑定的事件处理程序就会被执行。利用事件委托,我们能避免给大量子元素都绑定事件处理程序,减少内存占用,提高性能。

事件委托的原理

事件在 DOM 树中有三个阶段:捕获阶段、目标阶段和冒泡阶段。捕获阶段是从文档根节点开始,依次向下查找目标元素;目标阶段是事件到达目标元素;冒泡阶段是从目标元素开始,依次向上冒泡到文档根节点。事件委托主要利用的就是冒泡阶段。

代码示例

下面是一个简单的例子,演示了如何使用事件委托来处理列表项的点击事件。

// 获取父元素,这里是一个无序列表
const parentElement = document.getElementById('myList');

// 给父元素添加点击事件处理程序
parentElement.addEventListener('click', function(event) {
    // 判断事件的目标元素是否是列表项(li 元素)
    if (event.target.tagName === 'LI') {
        // 如果是列表项,就执行相应的操作,这里只是简单地在控制台输出点击的文本内容
        console.log('你点击了: ' + event.target.textContent);
    }
});

代码解释

  1. const parentElement = document.getElementById('myList');:这行代码通过 getElementById 方法获取了一个 ID 为 myList 的无序列表元素,这个无序列表就是我们的父元素。
  2. parentElement.addEventListener('click', function(event) { ... });:给父元素添加了一个点击事件处理程序。当在父元素或者其子元素上点击时,这个事件处理程序就会被触发。
  3. if (event.target.tagName === 'LI') { ... }:在事件处理程序中,通过 event.target 获取到实际触发事件的元素,然后判断这个元素的标签名是否为 LI。如果是,说明点击的是列表项。
  4. console.log('你点击了: ' + event.target.textContent);:如果点击的是列表项,就把列表项的文本内容输出到控制台。

事件委托的优点

  1. 减少内存占用:如果有大量的子元素需要绑定相同的事件处理程序,给每个子元素都绑定会占用大量的内存。而使用事件委托,只需要给父元素绑定一个事件处理程序就可以了。
  2. 动态添加元素时无需重新绑定事件:当动态添加新的子元素时,由于事件处理程序是绑定在父元素上的,新的子元素也能自动拥有相同的事件处理能力,不需要再为新元素单独绑定事件。

适用场景

  1. 列表项操作:比如上面的例子,当列表项很多时,使用事件委托可以方便地处理列表项的点击、鼠标悬停等事件。
  2. 动态生成元素:在动态生成元素的场景中,使用事件委托可以避免每次生成新元素都要绑定事件处理程序。例如,在一个聊天窗口中,新的消息不断添加进来,使用事件委托可以统一处理这些消息的点击事件。
  3. 表单元素:当表单中有多个输入框、按钮等元素时,可以使用事件委托来处理这些元素的事件,减少代码量。

除了点击事件,还有哪些事件可以使用事件委托机制?

事件委托机制并不局限于点击事件,只要是支持事件冒泡的事件都可以使用事件委托。下面为你介绍几种常见可使用事件委托机制的事件:

鼠标事件

  • mouseover 和 mouseout
    mouseover 事件在鼠标指针移动到元素上时触发,mouseout 事件在鼠标指针移出元素时触发。比如,在一个商品列表中,当鼠标悬停在某个商品上时改变其样式,就可以通过事件委托在父元素上监听这两个事件。
// 获取父元素
const productList = document.getElementById('productList');
// 给父元素添加 mouseover 事件处理程序
productList.addEventListener('mouseover', function (event) {
    if (event.target.classList.contains('product')) {
        event.target.style.backgroundColor = 'lightgray';
    }
});
// 给父元素添加 mouseout 事件处理程序
productList.addEventListener('mouseout', function (event) {
    if (event.target.classList.contains('product')) {
        event.target.style.backgroundColor = 'transparent';
    }
});
  • mousemove:当鼠标在元素内部移动时触发该事件。例如,在一个包含多个小方块的区域内,实时显示鼠标在每个小方块上的位置,可利用事件委托在父元素上监听。
const squareContainer = document.getElementById('squareContainer');
squareContainer.addEventListener('mousemove', function (event) {
    if (event.target.classList.contains('square')) {
        const x = event.offsetX;
        const y = event.offsetY;
        console.log(`在方块内的位置: (${x}, ${y})`);
    }
});

键盘事件

  • keydown 和 keyupkeydown 事件在按下键盘按键时触发,keyup 事件在释放键盘按键时触发。在一个包含多个输入框的表单中,统一处理用户按键操作,就可以使用事件委托。
const formElement = document.getElementById('myForm');
formElement.addEventListener('keydown', function (event) {
    if (event.target.tagName === 'INPUT') {
        console.log(`按下了按键: ${event.key}`);
    }
});

表单事件

  • change:当表单元素(如 inputselecttextarea)的值发生改变时触发该事件。在一个包含多个下拉框的页面中,通过事件委托在父元素上监听 change 事件,处理下拉框选项改变的情况。
const form = document.getElementById('myForm');
form.addEventListener('change', function (event) {
    if (event.target.tagName === 'SELECT') {
        console.log(`选择的值已改变为: ${event.target.value}`);
    }
});
  • submit:当表单提交时触发该事件。在一个包含多个表单的页面中,可以在父元素上监听 submit 事件,统一处理表单提交逻辑。
const formsContainer = document.getElementById('formsContainer');
formsContainer.addEventListener('submit', function (event) {
    if (event.target.tagName === 'FORM') {
        event.preventDefault();
        console.log('表单已提交');
        // 可以在这里添加表单提交后的处理逻辑
    }
});

触摸事件(适用于移动设备)

  • touchstart、touchmove 和 touchendtouchstart 事件在触摸屏幕时触发,touchmove 事件在触摸点在屏幕上移动时触发,touchend 事件在触摸点离开屏幕时触发。在一个包含多个可触摸元素的页面中,通过事件委托在父元素上监听这些触摸事件。
const touchContainer = document.getElementById('touchContainer');
touchContainer.addEventListener('touchstart', function (event) {
    if (event.target.classList.contains('touchable')) {
        console.log('开始触摸元素');
    }
});

总的来说,只要事件能够冒泡,都可以考虑使用事件委托机制来简化代码和提高性能。


http://www.kler.cn/a/593909.html

相关文章:

  • Quartz知识点总结
  • 使用 Python 爬取 TikTok 评论的实现与解析
  • 区跨链密码学
  • 基于 Swoole 的 PHP 异步框架评分与对比(按综合流行度排名)
  • 【MySQL】基本查询(第一弹)
  • 淘宝商品详情页API字段深度解析:如何精准提取SKU、销量、促销信息?
  • OAK相机入门(一):深度测距原理
  • 观察RenderDoc截帧UE时“Event”代表什么
  • Linux系统——crontab定时任务
  • 网络工程师的要求
  • 深蕾半导体IP-KVM产品方案解析
  • 云盘搭建笔记
  • 论文笔记——BiLLP框架
  • 【CAD二次开发】调试无法进入断点提示无可用源问题(非空心断点)
  • 【机器学习】什么是逻辑回归
  • 单调队列【C/C++】
  • JAVA接入DeepSeek大模型接口开发---阿里云的百炼模型
  • wpa_supplicant驱动初始化源码分析
  • 当Anaconda的安装路径与我想创建的conda虚拟环境路径不一致时,应该怎么操作?
  • Docker Compose部署MantisBT