深入解析:JS与Vue中事件委托(事件代理)的高效实现方法

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 深入解析:JS与Vue中事件委托(事件代理)的高效实现方法

一、事件委托(事件代理)

将原本需要绑定在子元素上的事件监听器委托在父元素上,让父元素充当事件监听的职务。


利用事件冒泡的特性,在父节点上响应事件,而不是在子节点上响应事件的技术。它能够改善性能,因为只需要在父元素上设置一次事件监听器,就可以管理同一类型的所有子元素的事件。


即事件从最深的节点开始,逐步向上传播。在事件冒泡过程中,父元素会捕获到子元素的事件,并进行分析。通过查看event对象的属性,可以确定是哪个子元素的事件,从而执行相应的处理逻辑。


使用事件委托能够避免对每个子元素单独设置事件监听器,降低了与DOM交互的次数,提高了页面的整体运行性能。同时,事件委托也具有更高的灵活性和可维护性,不需要操作大量的DOM元素。


在Vue中,可以利用v-on指令或@符号来绑定事件监听器,并在父元素上设置事件委托。例如,可以在父元素上设置一个click事件监听器,然后在子元素上绑定一个click事件,通过事件委托实现父元素对子元素事件的响应。

1、事件委托的优点
  • 节省内存(dom与js的关联),减少事件的注册
  • 增加子元素也无需再注册事件
2、事件委托的缺点

获取绑定的节点数据会相对麻烦一点

3、为什么要使用事件委托

在日常开发中,很经常我们会遇到个问题,就是在长列表数据较多的时候,而又需要对子元素注册一些事件(如onClick),就会造成比较大的内存开支,很耗费性能,也可能会造成页面卡顿等等;

所以可以通过在父元素上添加@click监听,而不是在子元素上注册事件;

如果数据量比较少,就可忽略不计;

此外,事件处理程序需要与 DOM 节点进行交互,访问 DOM 的次数越多,引起浏览器重绘和重排的次数也就越多,从而影响页面的性能。

4、事件委托实现原理

事件委托是利用事件的冒泡原理来实现的,大致可以分为三个步骤:

  1. 确定要添加事件元素的父级元素;
  2. 给父元素定义事件,监听子元素的冒泡事件;
  3. 使用 event.target 来定位触发事件冒泡的子元素。
5、DOM事件流

事件流描述的是从页面中接收事件的顺序。事件发生时会在元素节点之间按照特定的顺序传播,这个传播过程即DOM事件流。


比如:我们给页面中的一个div注册了单击事件,当你单击了div时,也就单击了body,单击了html,单击了document。



DOM 事件流会经历3个阶段:

  • 捕获阶段:事件从文档的根节点流向目标对象。

事件从最不精确的对象(document 对象)开始触发,然后到最精确(也可以在窗口级别捕获事件,不过必须由开发人员特别指定),与事件冒泡相反,事件会从最外层开始发生,直到最具体的元素。


  • 当前目标阶段:在目标对象上被触发。
  • 冒泡阶段:回溯到文档的根节点。

微软提出了名为事件冒泡的事件流。事件按照从最特定的事件目标到最不特定的事件目标(document对象)的顺序触发。

6、事件委托的实现方法
1、vue写法
1.1、html代码
<div id="app">
    <div id="event-agent" @click="eventAgent">
        <p v-for="(item, index) in list" :key="index" :data-name="item.name" :data-index="index">{{item.name}}</p>
    </div>
</div>

> 获取节点参数 (data-index、data-name),则在 $event.target.dataset  { index: 'xxx', name: 'xxx' } 中取值

1.2、js代码
data() {
    return { 
         list: [
             { id: 1, name: 'kmj1'},
             { id: 2, name: 'kmj2'},
             { id: 3, name: 'kmj3'},
             { id: 4, name: 'kmj4'}
         ]   
    }
},
methods: { 
    // 事件委托
    eventAgent(e) {
       const target = e.target; 
       console.log(target )
       // 注意 e.target.nodeName 的元素名是大写的
       if (target  && target.nodeName === "P") {
           const dataset = target .dataset;
           console.log('$event.target.dataset : ' dataset ); // $event.target.dataset :  { name: 'xxx', index: 'xxx' }
       }
    }
}
2、原生的写法其实也差不多:
2.1、html代码
<div id="event-agent">
    <p :data-name="Item1" :data-index="0">Item 1</p>
    <p :data-name="Item2" :data-index="1">Item 2</p>
    <p :data-name="Item3" :data-index="2">Item 3</p>
    <p :data-name="Item4" :data-index="3">Item 4</p>
    <p :data-name="Item5" :data-index="4">Item 5</p>
    <p :data-name="Item6" :data-index="5">Item 6</p>
</div>
2.2、js代码
1.document.getElementById( "event-agent").onclick = function(event){ 
    // 兼容Ie的写法
    event = event || window.event;
    var  target = event.target || event.srcElement;  
    // 注意 e.target.nodeName 的元素名是大写的
    if (target  && target.nodeName === "P") {
       const dataset = target .dataset;
       console.log('$event.target.dataset : ' dataset ); // $event.target.dataset :  { name: 'xxx', index: 'xxx' }
    }
}; 
 
// 也可以用这种方式,其实都差不多的:
// 冒泡阶段处理程序  
document.getElementById( "event-agent").addEventListener( "click", (e) => {},   false);
// 捕获阶段处理程序
document.getElementById( "event-agent").addEventListener( "click", (e) => {},   true);


二、阻止事件冒泡

W3C的方法是e.stopPropagation(),IE则是使用e.cancelBubble = true。 stopPropagation是事件的一个方法,作用是阻止目标元素的事件冒泡,但是不会组织默认行为。

 

function stopBubble(e) { 
//如果提供了事件对象,则这是一个非IE浏览器 
if ( e && e.stopPropagation ) 
    //因此它支持W3C的stopPropagation()方法 
    e.stopPropagation(); 
else 
    //否则,我们需要使用IE的方式来取消事件冒泡 
    window.event.cancelBubble = true; 
}


三、取消默认事件

W3C的方法是e.preventDefault(),IE则是使用e.returnValue = false。 preventDefault()是事件对象(Event)的一个方法,作用是取消一个目标元素的默认行为。既然是默认行为,那么元素必须有默认行为才能被取消,如果元素本身就没有默认行为,调用自然就无效了。什么元素有默认行为呢?如链接\<a href="">,提交按钮<input type=”submit”>等,这些都有默认行为。


 

function preventDefault(e){
    if(e && e.preventDefault){
        e.preventDefault();
    }
    else{
        window.event.returnValue = false;
    }
    return false;
}


四、总结

要使用事件委托,需要保证事件能够发生冒泡,适合使用事件委托的事件有 click、mousedown、mouseup、keydown、keyup、keypress 等。需要注意的是,虽然 mouseover 和 mouseout 事件也会发生事件冒泡,但处理起来非常麻烦,所以不推荐在 mouseover 和 mouseout 事件中使用事件委托。


另外,对于不会发生事件冒泡的事件(例如 load、unload、abort、focus、blur 等),则无法使用事件委托。


目录
相关文章
|
29天前
|
JavaScript 前端开发 程序员
前端原生Js批量修改页面元素属性的2个方法
原生 Js 的 getElementsByClassName 和 querySelectorAll 都能获取批量的页面元素,但是它们之间有些细微的差别,稍不注意,就很容易弄错!
|
9天前
|
安全 Ubuntu Shell
深入解析 vsftpd 2.3.4 的笑脸漏洞及其检测方法
本文详细解析了 vsftpd 2.3.4 版本中的“笑脸漏洞”,该漏洞允许攻击者通过特定用户名和密码触发后门,获取远程代码执行权限。文章提供了漏洞概述、影响范围及一个 Python 脚本,用于检测目标服务器是否受此漏洞影响。通过连接至目标服务器并尝试登录特定用户名,脚本能够判断服务器是否存在该漏洞,并给出相应的警告信息。
127 84
|
27天前
|
监控 JavaScript Java
Node.js中内存泄漏的检测方法
检测内存泄漏需要综合运用多种方法,并结合实际的应用场景和代码特点进行分析。及时发现和解决内存泄漏问题,可以提高应用的稳定性和性能,避免潜在的风险和故障。同时,不断学习和掌握内存管理的知识,也是有效预防内存泄漏的重要途径。
122 52
|
8天前
|
存储 Java 开发者
浅析JVM方法解析、创建和链接
上一篇文章《你知道Java类是如何被加载的吗?》分析了HotSpot是如何加载Java类的,本文再来分析下Hotspot又是如何解析、创建和链接类方法的。
|
1月前
|
JavaScript 前端开发 索引
js中DOM的基础方法
【10月更文挑战第31天】这些DOM基础方法是操作网页文档结构和实现交互效果的重要工具,通过它们可以动态地改变页面的内容、样式和行为,为用户提供丰富的交互体验。
|
1月前
|
缓存 JavaScript UED
js中BOM中的方法
【10月更文挑战第31天】
|
20天前
|
负载均衡 网络协议 算法
Docker容器环境中服务发现与负载均衡的技术与方法,涵盖环境变量、DNS、集中式服务发现系统等方式
本文探讨了Docker容器环境中服务发现与负载均衡的技术与方法,涵盖环境变量、DNS、集中式服务发现系统等方式,以及软件负载均衡器、云服务负载均衡、容器编排工具等实现手段,强调两者结合的重要性及面临挑战的应对措施。
49 3
|
28天前
|
缓存 JavaScript 前端开发
JavaScript 与 DOM 交互的基础及进阶技巧,涵盖 DOM 获取、修改、创建、删除元素的方法,事件处理,性能优化及与其他前端技术的结合,助你构建动态交互的网页应用
本文深入讲解了 JavaScript 与 DOM 交互的基础及进阶技巧,涵盖 DOM 获取、修改、创建、删除元素的方法,事件处理,性能优化及与其他前端技术的结合,助你构建动态交互的网页应用。
41 5
|
1月前
|
JSON PHP 数据格式
PHP解析配置文件的常用方法
INI文件是最常见的配置文件格式之一。
49 12
|
29天前
|
JavaScript 前端开发
js中的bind,call,apply方法的区别以及用法
JavaScript中,`bind`、`call`和`apply`均可改变函数的`this`指向并传递参数。其中,`bind`返回一个新函数,不立即执行;`call`和`apply`则立即执行,且`apply`的参数以数组形式传递。三者在改变`this`指向及传参上功能相似,但在执行时机和参数传递方式上有所区别。
26 1

推荐镜像

更多
下一篇
DataWorks