Vue框架Element的事件传递broadcast和dispatch方法分析

简介: Vue Elemen broadcast dispatch

前言

最近在学习饿了么的Vue前端框架Element,发现其源码中大量使用了broadcastdispatch方法,而Element使用的是Vue2.0版本,众所周知在Vue 1.0升级到2.0中去除了$broadcast$dispatch方法。

所以在Element框架源码中将这两个函数重写实现了一遍,并采用的是minix的方式植入每个组件的代码中。

但是Element的这两个函数虽然与官方同名,但功能却有所差异,遂有本文,简单分析一下区别于用途。

Element的broadcast功能分析

功能简述

  1. 在Element中broadcast(事件广播)方法需要3个参数,componentName组件名称, eventName事件名,和params数据。
  2. broadcast是寻找所有子孙组件中,组件名为componentName的组件,若找到在其组件上触发($emit)eventName的事件方法,数据为params
  3. 假设若有3个子组件或孙子组件的组件名为指定的componentName的话,这三个组件上都会触发其指定的事件方法。

源码对比

vue 1.0的官方$broadcast的实现源码:

/**
* Recursively broadcast an event to all children instances.
*
* @param {String|Object} event
* @param {...*} additional arguments
*/
Vue.prototype.$broadcast = function (event) {
 var isSource = typeof event === 'string';
 event = isSource ? event : event.name;
 // if no child has registered for this event,
 // then there's no need to broadcast.
 if (!this._eventsCount[event]) return;
 var children = this.$children;
 var args = toArray(arguments);
 if (isSource) {
   // use object event to indicate non-source emit
   // on children
   args[0] = { name: event, source: this };
 }
 //遍历所有一级子组件
 for (var i = 0, l = children.length; i < l; i++) {
   var child = children[i];
   //在每个组件上均触发指定的事件
   var shouldPropagate = child.$emit.apply(child, args);
   //若事件响应函数返回true才会向孙子组件继续广播
   if (shouldPropagate) {
     child.$broadcast.apply(child, args);
   }
 }
 return this;
};

Element的broadcast的实现源码:

broadcast(componentName, eventName, params) {
 broadcast.call(this, componentName, eventName, params);
 function broadcast(componentName, eventName, params) {
   //遍历所有子组件
   this.$children.forEach(child => {
     var name = child.$options.componentName;
     //寻找符合指定名称的子组件
     if (name === componentName) {
       //在符合的自组件上触发的事件,但是不会再继续寻找符合名称的组件的子集,原因?
       child.$emit.apply(child, [eventName].concat(params));
     } else {
       //不符合继续寻找他的子集(即孙子组件)
       broadcast.apply(child, [componentName, eventName].concat([params]));
     }
   });
 }
}

官方的$broadcast用途的解释为:

广播事件,通知给当前实例的全部后代。因为后代有多个枝杈,事件将沿着各“路径”通知。每条路径上的通知在触发一个监听器后停止,除非它返回 true。

Element的broadcast与Vue1.0官方的区别对比:

  1. 官方的$broadcast的参数只有两个,event事件名和args事件数据。Element为三个,多一个组件名。
  2. 官方的$broadcast触发方式是默认只触发子代组件,不触发孙子代组件,如果子代创建了监听且返回了true,才会向孙子代组件传递事件。而Element是直接向所有子孙后代组件传递,也没有返回值判定。
  3. 最重要的区别在于用途。Element的broadcast虽然与官方的同名,但是通过分析源码可以看出Element的用途应该是 远程调用 或应取名叫childEmit,用途是调用/触发指定子孙组件的事件。而非广义上的“广播”的概念。

最后,在Element的源码中如果找到了指定名称的组件,并在其身上触发了事件后,不会继续在其身上查询他的子组件,从用途上来讲应该是找到所有符合名称的子孙组件并触发,所以为何会这样原因不明。也许在Element的组件系统设计里面,没有自身套自身的情况?或是并不想在继续触发下级?需要再仔细分析才可了。

Element的dispatch功能分析

功能简述

通过前面分析的$broadcast可以大致推导出Element中的dispatch的主要功能。

依然是以寻找所有父级,直到找到要找的父组件,并在其身上触发指定事件。

整体功能更类似jQuery的closest方法。

源码对比

vue 1.0的官方$dispatch的实现源码:

/**
* Recursively propagate an event up the parent chain.
*
* @param {String} event
* @param {...*} additional arguments
*/
Vue.prototype.$dispatch = function (event) {
 var shouldPropagate = this.$emit.apply(this, arguments);
 if (!shouldPropagate) return;
 var parent = this.$parent;
 var args = toArray(arguments);
 // use object event to indicate non-source emit
 // on parents
 args[0] = { name: event, source: this };
 while (parent) {
   shouldPropagate = parent.$emit.apply(parent, args);
   parent = shouldPropagate ? parent.$parent : null;
 }
 return this;
};

Element的dispatch的实现:

dispatch(componentName, eventName, params) {
 var parent = this.$parent || this.$root;
 var name = parent.$options.componentName;
 //寻找父级,如果父级不是符合的组件名,则循环向上查找
 while (parent && (!name || name !== componentName)) {
   parent = parent.$parent;
   if (parent) {
     name = parent.$options.componentName;
   }
 }
 //找到符合组件名称的父级后,触发其事件。整体流程类似jQuery的closest方法
 if (parent) {
   parent.$emit.apply(parent, [eventName].concat(params));
 }
},

最后

通过学习Element源码中的broadcastdispatch的实现功能,从能力角度而言,Element是将官方的 事件广播/事件派发 的功能弱化了,属于是“阉割版”的。但是从实际开发过程中的易用性角度而言,Element的做法更贴合我们日常开发过程中的需求,如父组件调用组件的方法(如全选复选框等),子组件向父组件通知变更(如表单校验等)。

Element是很优秀的Vue框架,值得深入学习来了解更深的Vue使用以及组件化思路。

目录
相关文章
|
2月前
|
JavaScript
Vue中如何实现兄弟组件之间的通信
在Vue中,兄弟组件可通过父组件中转、事件总线、Vuex/Pinia或provide/inject实现通信。小型项目推荐父组件中转或事件总线,大型项目建议使用Pinia等状态管理工具,确保数据流清晰可控,避免内存泄漏。
308 2
|
1月前
|
缓存 JavaScript
vue中的keep-alive问题(2)
vue中的keep-alive问题(2)
285 137
|
5月前
|
人工智能 JavaScript 算法
Vue 中 key 属性的深入解析:改变 key 导致组件销毁与重建
Vue 中 key 属性的深入解析:改变 key 导致组件销毁与重建
782 0
|
5月前
|
JavaScript UED
用组件懒加载优化Vue应用性能
用组件懒加载优化Vue应用性能
|
6月前
|
JavaScript 数据可视化 前端开发
基于 Vue 与 D3 的可拖拽拓扑图技术方案及应用案例解析
本文介绍了基于Vue和D3实现可拖拽拓扑图的技术方案与应用实例。通过Vue构建用户界面和交互逻辑,结合D3强大的数据可视化能力,实现了力导向布局、节点拖拽、交互事件等功能。文章详细讲解了数据模型设计、拖拽功能实现、组件封装及高级扩展(如节点类型定制、连接样式优化等),并提供了性能优化方案以应对大数据量场景。最终,展示了基础网络拓扑、实时更新拓扑等应用实例,为开发者提供了一套完整的实现思路和实践经验。
836 77
|
4月前
|
人工智能 JSON JavaScript
VTJ.PRO 首发 MasterGo 设计智能识别引擎,秒级生成 Vue 代码
VTJ.PRO发布「AI MasterGo设计稿识别引擎」,成为全球首个支持解析MasterGo原生JSON文件并自动生成Vue组件的AI工具。通过双引擎架构,实现设计到代码全流程自动化,效率提升300%,助力企业降本增效,引领“设计即生产”新时代。
407 1
|
4月前
|
JavaScript 安全
在 Vue 中,如何在回调函数中正确使用 this?
在 Vue 中,如何在回调函数中正确使用 this?
259 0
|
5月前
|
JavaScript 前端开发 开发者
Vue 自定义进度条组件封装及使用方法详解
这是一篇关于自定义进度条组件的使用指南和开发文档。文章详细介绍了如何在Vue项目中引入、注册并使用该组件,包括基础与高级示例。组件支持分段配置(如颜色、文本)、动画效果及超出进度提示等功能。同时提供了完整的代码实现,支持全局注册,并提出了优化建议,如主题支持、响应式设计等,帮助开发者更灵活地集成和定制进度条组件。资源链接已提供,适合前端开发者参考学习。
469 17
|
5月前
|
JavaScript 前端开发 UED
Vue 手风琴实现的三种常用方式及长尾关键词解析
手风琴效果是Vue开发中常见的交互组件,可节省页面空间、提升用户体验。本文介绍三种实现方式:1) 原生Vue结合数据绑定与CSS动画;2) 使用Element UI等组件库快速构建;3) 自定义指令操作DOM实现独特效果。每种方式适用于不同场景,可根据项目需求选择。示例包括产品特性页、后台菜单及FAQ展示,灵活满足多样需求。附代码示例与资源链接,助你高效实现手风琴功能。
323 10

热门文章

最新文章