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

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 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 等),则无法使用事件委托。


目录
相关文章
|
9天前
|
JavaScript 前端开发 Go
CSS 与 JS 对 DOM 解析和渲染的影响
【10月更文挑战第16天】CSS 和 JS 会在一定程度上影响 DOM 解析和渲染,了解它们之间的相互作用以及采取适当的优化措施是非常重要的。通过合理的布局和加载策略,可以提高网页的性能和用户体验,确保页面能够快速、流畅地呈现给用户。在实际开发中,要根据具体情况进行权衡和调整,以达到最佳的效果。
|
5天前
|
人工智能
歌词结构的巧妙安排:写歌词的方法与技巧解析,妙笔生词AI智能写歌词软件
歌词创作是一门艺术,关键在于巧妙的结构安排。开头需迅速吸引听众,主体部分要坚实且富有逻辑,结尾则应留下深刻印象。《妙笔生词智能写歌词软件》提供多种 AI 功能,帮助创作者找到灵感,优化歌词结构,写出打动人心的作品。
|
8天前
|
缓存 监控 前端开发
JavaScript 实现大文件上传的方法
【10月更文挑战第17天】通过以上步骤和方法,我们可以实现较为可靠和高效的大文件上传功能。当然,具体的实现方式还需要根据实际的应用场景和服务器要求进行调整和优化。
|
12天前
|
存储 算法 Java
解析HashSet的工作原理,揭示Set如何利用哈希算法和equals()方法确保元素唯一性,并通过示例代码展示了其“无重复”特性的具体应用
在Java中,Set接口以其独特的“无重复”特性脱颖而出。本文通过解析HashSet的工作原理,揭示Set如何利用哈希算法和equals()方法确保元素唯一性,并通过示例代码展示了其“无重复”特性的具体应用。
30 3
|
6天前
|
人工智能
写歌词的技巧和方法全解析:开启你的音乐创作之旅,妙笔生词智能写歌词软件
怀揣音乐梦想,渴望用歌词抒发情感?掌握关键技巧,你也能踏上创作之旅。灵感来自生活点滴,主题明确,语言简洁,韵律和谐。借助“妙笔生词智能写歌词软件”,AI辅助创作,轻松写出动人歌词,实现音乐梦想。
|
5天前
|
存储 前端开发 JavaScript
JavaScript垃圾回收机制深度解析
【10月更文挑战第21】JavaScript垃圾回收机制深度解析
86 59
|
20小时前
|
JavaScript 前端开发 Go
异步加载 JS 的方法
【10月更文挑战第24天】异步加载 JavaScript 是提高网页性能和用户体验的重要手段。通过使用不同的方法和技术,可以实现灵活、高效的异步加载 JavaScript。在实际应用中,需要根据具体情况选择合适的方法,并注意处理可能出现的问题,以确保网页能够正常加载和执行。
|
5天前
|
JavaScript 前端开发 开发者
理解Vue实例:生命周期钩子全面解析
【10月更文挑战第21天】理解Vue实例:生命周期钩子全面解析
12 4
|
3天前
|
缓存 前端开发 JavaScript
"面试通关秘籍:深度解析浏览器面试必考问题,从重绘回流到事件委托,让你一举拿下前端 Offer!"
【10月更文挑战第23天】在前端开发面试中,浏览器相关知识是必考内容。本文总结了四个常见问题:浏览器渲染机制、重绘与回流、性能优化及事件委托。通过具体示例和对比分析,帮助求职者更好地理解和准备面试。掌握这些知识点,有助于提升面试表现和实际工作能力。
13 1
|
6天前
|
安全 Java
Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧
【10月更文挑战第20天】Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧,包括避免在循环外调用wait()、优先使用notifyAll()、确保线程安全及处理InterruptedException等,帮助读者更好地掌握这些方法的应用。
8 1

推荐镜像

更多