Vue框架Element的事件传递broadcast和dispatch方法分析
前言
最近在学习饿了么的Vue前端框架Element,发现其源码中大量使用了broadcast和dispatch方法,而Element使用的是Vue2.0版本,众所周知在Vue 1.0升级到2.0中去除了$broadcast和$dispatch方法。
所以在Element框架源码中将这两个函数重写实现了一遍,并采用的是minix的方式植入每个组件的代码中。
但是Element的这两个函数虽然与官方同名,但功能却有所差异,遂有本文,简单分析一下区别于用途。
Element的broadcast功能分析
功能简述
- 在Element中broadcast(事件广播)方法需要3个参数,
componentName组件名称,eventName事件名,和params数据。 - broadcast是寻找所有子孙组件中,组件名为
componentName的组件,若找到在其组件上触发($emit)eventName的事件方法,数据为params。 - 假设若有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官方的区别对比:
- 官方的
$broadcast的参数只有两个,event事件名和args事件数据。Element为三个,多一个组件名。 - 官方的
$broadcast触发方式是默认只触发子代组件,不触发孙子代组件,如果子代创建了监听且返回了true,才会向孙子代组件传递事件。而Element是直接向所有子孙后代组件传递,也没有返回值判定。 - 最重要的区别在于用途。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源码中的broadcast和dispatch的实现功能,从能力角度而言,Element是将官方的 事件广播/事件派发 的功能弱化了,属于是“阉割版”的。但是从实际开发过程中的易用性角度而言,Element的做法更贴合我们日常开发过程中的需求,如父组件调用组件的方法(如全选复选框等),子组件向父组件通知变更(如表单校验等)。
Element是很优秀的Vue框架,值得深入学习来了解更深的Vue使用以及组件化思路。
Vue框架Element的事件传递broadcast和dispatch方法分析的更多相关文章
- Vue 框架-03-键盘事件、健值修饰符、双向数据绑定
Vue 框架-03-键盘时间及健值修饰符 一.键盘事件,当按键盘时,在控制台输出提示 html 源码: <!DOCTYPE html> <html> <head> ...
- laravel5.1框架基础之Blade模板继承简单使用方法分析
本文实例讲述了laravel5.1框架基础之Blade模板继承简单使用方法.分享给大家供大家参考,具体如下: 模板继承什么用? 自然是增强基础页面的复用,有利于页面文档的条理,也便于更改多处使用的内容 ...
- Vue框架Element UI教程-axios请求数据
Element UI手册:https://cloud.tencent.com/developer/doc/1270 中文文档:http://element-cn.eleme.io/#/zh-CN gi ...
- Android事件传递机制(转)
Android事件构成 在Android中,事件主要包括点按.长按.拖拽.滑动等,点按又包括单击和双击,另外还包括单指操作和多指操作.所有这些都构成了Android中的事件响应.总的来说,所有的事件都 ...
- Android事件传递机制详解及最新源码分析——ViewGroup篇
版权声明:本文出自汪磊的博客,转载请务必注明出处. 在上一篇<Android事件传递机制详解及最新源码分析--View篇>中,详细讲解了View事件的传递机制,没掌握或者掌握不扎实的小伙伴 ...
- 细说Android事件传递
一.View的dispatchTouchEvent和onTouchEvent 探讨Android事件传递机制前,明确android的两大基础控件类型:View和ViewGroup.View即普通的控件 ...
- Vue 框架-02-事件:点击, 双击事件,鼠标移上事件
Vue 框架-02-事件:点击, 双击事件,鼠标移上事件 1.单击事件:v-on:click 源码 app2.js : //实例化 vue 对象 new Vue({ //注意代码格式 //el:ele ...
- Vue框架(一)——Vue导读、Vue实例(挂载点el、数据data、过滤器filters)、Vue指令(文本指令v-text、事件指令v-on、属性指令v-bind、表单指令v-model)
Vue导读 1.Vue框架 vue是可以独立完成前后端分离式web项目的js框架 三大主流框架之一:Angular.React.Vue vue:结合其他框架优点.轻量级.中文API.数据驱动.双向绑定 ...
- Vue框架:挂载点-过滤器-事件指令-表单指令
近期学习安排 1.Vue框架 前台html+css+js框架,是不同于js与JQuery的数据驱动框架, 学习的知识点:指令 | 实例成员 | vue项目 2.drf框架 django的插件,完成前 ...
随机推荐
- Nginx Image Module图片缩略图 水印处理模块
Nginx Image Module图片缩略图 水印处理模块 下载Tengine tar -zxvf tengine-1.4.5.tar.gz cd tengine-1.4.5 下载Nginx tar ...
- MySQL的mysql_insert_id和LAST_INSERT_ID
摘要:mysql_insert_id和LAST_INSERT_ID二者作用一样,均是返回最后插入值的ID 值 1 mysql_insert_id 一.PHP获取MYSQL新插入数据的ID mysql ...
- js-权威指南学习笔记9
第九章 类和模块 1.在JS中,类的实现是基于其原型继承机制的,如果两个实例都从同一个原型对象上继承了属性,我们说它们是同一个实例. 2.常见的编程约定:定义构造函数既是定义类,并且类名首字母要大写. ...
- wex5 实战 苹果左滑删除与长按编辑
用了多年苹果,习惯了苹果的左滑删除与长按编辑,特别是短信什么的,很多安卓界面也采用了类似方式. 我的想法突如其来,用wex5也设计一个这样的功能,可以吗? 那句广告词,没有什么不可能. 呵呵. 一 ...
- java 生成不重复的随机数
import java.text.SimpleDateFormat;import java.util.Date; public class Test2 { public static void mai ...
- libtask channel机理及调度理解
学习golang的时候libtask库的代码是一定要看的,需要深入理解chan和携程的运行机制,下面就结合libtask的源码说明下运行原理,如果理解的有偏差欢迎指正 下面是libtask中Chann ...
- STM8建立IAR工程
STM8是意法半导体公司出的增强型八位单片机,性能比51单片机强大,而且价格便宜,在商业应用中很受欢迎 在STM8的开发工程中主要有两种开发工具链.第一是使用IAR开发环境,第二十使用cosmic+s ...
- 苹果App Store开发者帐户从申请,验证,到发布应用(2)
app store付费 上面已经介绍了app store id的注册了,下面在注册基础上,介绍一下app store的付费. 在上面注册成功之后,会收到一封邮件. 1.收到邮件Thank Yo ...
- git如何正确回滚代码
git如何正确回滚代码 方法一,删除远程分支再提交 ①首先两步保证当前工作区是干净的,并且和远程分支代码一致 $ git co currentBranch $ git pull origin curr ...
- iOS数据存储
[reference]http://www.infoq.com/cn/articles/data-storage-in-ios 谈到数据储存,首先要明确区分两个概念,数据结构和储存方式.所谓数据结构就 ...