宝哥软件园

详细解释情侣属性$dispatch和$broadcast in Vue

编辑:宝哥软件园 来源:互联网 时间:2021-08-27

00前言

作为一个耦合属性,$dispatch和$broadcast主要用于实现Vue 1.0中基于组件树结构的事件流通信。——以向上冒泡或向下冒泡的形式传输事件流,实现嵌套的父子组件通信。然而,由于其明显的功能缺陷,它在Vue 2.0中被删除。虽然Vue官网不再支持使用$dispatch和$broadcast的组件通信,但它被封装在很多基于Vue的UI框架中,包括element-ui、iview等。

那么,$dispatch和$broadcast是如何工作的,底层是如何实现的?接下来,我们来详细说说吧!

01美元派单的详细说明

为了溯源,我们先去Vue 1.0的文档,观察它的概念。

概念:

调度一个事件,首先在实例本身上触发它,然后沿着父链向上传播。当触发父事件侦听器时,传播停止,除非该侦听器返回strue。任何额外的参数都将被传递到侦听器的回调函数中。

以上英文定义来自Vue 1.0的官方文档,大致意思是派单是一个事件,会先在自己的实例上触发,然后向上扩散到父链。当它触发父组件上的事件侦听器时,传播停止,除非侦听器返回true。任何其他参数都被传递给侦听器的回调函数。

参数:

调度接收两个参数:事件是事件名称,以及[.args]是事件被触发时传递给回调函数的参数。

* *示例:

//创建父组件var parent=new Vue();//创建一个child1组件,其父组件指向parent var child 1=new vue({ parent : parent });//创建一个child2组件,其父组件指向child 1 varchild 2=new vue({ parent : child 1 });//监听父组件中名为test的事件,绑定一个回调函数父。$ on ('test ',function(){ console . log(' parent notified ');});//监听child1组件中名为test的事件,绑定一个回调函数Child1。$ on ('test ',function(){ console . log(' child 1 notified ');});//监听child2组件中名为test的事件,绑定一个回调函数Child2。$ on ('test ',function(){ console . log(' child 2 notified ');});话虽如此,父母、子女1和子女2之间的关系可以如下图所示:

//触发测试事件child2。$dispatch('test ')通过child2组件中的dispatch实现;//执行child2时,事件执行将输出以下结果////-' child 2 notified '//-' child 1 notified '。$ dispatch(' test ');首先会触发child2组件中监控的测试事件的回调函数,输出‘child 2 notified’。根据上述官方文档的定义,事件将沿着组件关系链向上传递,然后传递给child1组件,触发监控事件输出‘child 1 notified’,但侦听器没有返回true。因此,事件传输到这里就结束了,最终的输出结果只有‘child 2 notified’和‘child 1 notified’。

Vue 1.0的正式实现

在vue 1.0版本中,$dispatch实现的源代码放在/src/instance/api/events.js文件中,代码很简单:

/* * *递归地将事件向上传播到父链。*递归传播父链上的事件。* @ param {string}事件* @ param { 0.*}附加参数*///$ dispatch方法是在vue的原型上定义的//接受一个字符串类型的事件名称Vue。原型。$ dispatch=function(event){//首先执行$emit触发器事件,并将返回值保存在shouldPropagate var应该propagate=this中。$ emitapply (this,Arguments) //如果第一次执行的$emit方法返回的值不为真,则直接返回//如果返回值不为真,则表示组件逻辑不希望事件继续传递给父组件if(!ShouldPropagate) return //如果$emit方法的返回值第一次为true,则获取父组件实例var parent=this。$parent //将函数接受的参数转换为数组var args=toArray(arguments) //使用object事件指示parents上的非源emit根据传入事件名称的参数将其组装为object args[0]={name:事件。Source: this} //循环知道组件的父组件是while(parent){//Execute $ emit触发器事件应该传播=parent。$emit.apply (parent,args)//如果父组件$emit返回true,继续递归父组件,否则停止循环parent=shouldPropagate?家长。$parent : null} //最后返回当前组件实例的实现返回this}element-ui

在element-ui中,$dispatch实现的源代码放在/src/mixins/emitter.js文件中,代码非常简单:

//定义调度方法,接受三个参数,即:组件名、要触发的事件名、回调函数{//传递的参数调度(组件名、事件名、params)基于当前组件获取父组件实例,其中父组件实例和根组件实例兼容处理为varparent=this。$ parent | |这个。$ root//获取组件的名称var name=parent。$options.componentname通过父组件的$ option属性;//当父组件实例相对于当前组件存在,并且父组件的名称不存在或者父组件的名称不等于传入的组件名称时,执行while循环(parent(!名字||名字!==componentName)) {//记录父组件parent=parent。$ parent//当父组件的父组件存在时,如果(parent) {name=parent,则获取父组件的名称。$ options.componentname} }//当循环结束时,parent的值是最终匹配的组件实例if (parent) {//当parent的值存在时,调用由parent实例、eventName和params参数//组成的数组中的$emit方法//pass触发事件parent。$ emit.apply(父级,[eventname]。concat(。}}差异分析

仔细阅读了实现$dispatch模式的两个版本的代码后,是否发现两个版本的实现和功能还是有很大的差异?

1.接受参数:Vue实现版本只接受一个string类型的事件名称作为参数,而element-ui实现版本接受三个参数,即:需要触发事件的组件名称、要触发的事件名称、回调函数传递的参数;

2.实现功能:Vue实现版本的触发事件会一直向上传递到组件链,知道父组件中的监听器不返回true,在此期间,所有组件都会响应事件,包括当前组件本身,而element-ui实现版本会不断基于当前组件遍历父组件,直到找到与接受的组件名称匹配的,才会停止遍历,触发匹配组件中的监听事件。

10美元广播的详细解释

$dispatch方法的实现以及Vue实现版本和element-ui实现版本之间的区别已经在上面详细描述过了。现在,我们应该谈谈$广播。毕竟他们是情侣属性。

概念

广播向下传播到当前实例的所有后代的事件。由于后代扩展成多个子树,事件传播将遵循许多不同的“路径”。除非回调返回true,否则当沿着每个路径激发侦听器回调时,该路径的传播将停止。

广播是向下传播到当前实例的所有后代的事件。由于后代被扩展成多个子树,事件传播将遵循许多不同的路径。除非回调返回true,否则当沿着该路径触发侦听器回调时,每个路径的传播都将停止。

参数

广播接收两个参数:事件是事件名称,以及[.args]是事件被触发时传递给回调函数的参数。

例子

//创建父组件实例var parent=new Vue()//创建child1组件实例,其父组件指向parent var child 1=new Vue({ parent : parent })//创建child2组件实例。父组件指向parent var child 2=new vue({ parent : parent })//以创建child3组件实例。其父组件指向child 2 archid 3=new vue({ parent : child 2 })//侦听child1组件中名为test的事件,并绑定回调函数child1。$on('test ',Function(){ console . log(' child 1 notified ')})//侦听child2组件中名为test的事件,并绑定一个回调函数child2。$on('test ',Function(){ console . log(' child 2 notified ')})//侦听child3组件中名为test的事件,并绑定一个回调函数child3。$on('test ',function(){ console . log(' child 3 notified ')})的四个组件父级、子级1、子级2和子级3之间的关系如下图所示:

家长。$ broadcast(' test ')///-' child 1 notified '//-' child 2 notified '在执行parent时。$ broadcast(' test ');事件流将从父组件转移到父组件的子组件。根据事件绑定的顺序,虽然父组件有两个子组件,处于同一级别的child1和child2,但是事件流将首先触发child1中的绑定事件,然后输出‘child 1 notified’。然后,当事件流到达child2组件时,它将触发child2组件中的绑定事件,并输出“child2 notified”。此时,child2组件中的侦听器没有返回true,因此事件传递在此结束,最终输出结果只有“child1已通知”和“child2已通知”。

Vue 1.0的正式实现

在vue 1.0版本中,$broadcast实现的源代码放在/src/instance/api/events.js文件中,代码很简单:

/* * *递归地向所有子实例广播一个事件。*递归地向所有子实例广播事件。* @ param {string | object}事件* @ param { 0.*}附加参数*///$ dispatch方法是在Vue//Accept a event Vue的原型上定义的。原型。$ broadcast=function(event){//获取传入事件的类型,判断是否是字符串var is source=事件的类型==' string '//更正事件的值,当接受的事件类型为字符串时直接使用,如果不是字符串,那么name属性event=isSource?事件:事件。name//如果没有孩子注册这个活动,//那就没必要播了。//如果当前组件的子组件没有注册事件,将直接返回,不广播if(!这个。_ eventcount [event])返回//Get子组件var children=this。$children //将函数接受的参数转换为数组var args=toArray(arguments) //如果传入事件是字符串If(is source){//使用object event在children上指示非source emit////将其组装为object args[0]={name: event根据传入事件名称的参数,Source: this}} //Loop子组件for (var i=0,l=children.lengthI l;I){ var child=children[I]//call $ emit触发器事件var应该传播=child。$ emitapply (child,Args) //如果(shouldPropagate) {//如果调用$emit返回的值为true,则递归孙子组件将继续广播child。$广播。Apply (child,args)} }//最后,返回当前组件的这个}element-ui实现。

在element-ui中,$broadcast实现的源代码放在/src/mixins/emitter.js文件中,代码非常简单:

//定义广播方法,接受三个参数,即:组件名、要触发的事件名、参数函数广播(组件名、事件名、Params) {//Loop this。$ children . foreach(child={//获取每个子组件的名称var name=child。$ options.componentname//如果(name===componentName) {//如果子组件的名称等于传入的组件名称,则调用$emit触发器事件子级,则确定子组件的名称是否等于传入的组件名称。$ emit.apply(子项,[事件名称]。concat(params));} else {//如果子组件的名称不等于传入的组件名称,则递归遍历并调用广播孙子组件broadcast.apply (child,[组件名称,事件名称])。concat([params]);} });}方差分析

像前面提到的$dispatch一样,这里的$broadcast的两个实现版本之间有巨大的差异:

1.接受参数:Vue实现版本只接受一个string类型的事件名称作为参数,而element-ui实现版本接受三个参数,即:需要触发事件的组件名称、要触发的事件名称、回调函数传递的参数;

2.实现功能:Vue实现的$broadcast的触发方式是默认只触发子组件,不触发孙子组件。如果子组件创建了一个监视器并返回true,事件将被传输到孙子组件。element-ui的实现版本直接传递给所有的后代组件,在得到的子组件名等于传入的组件名之前,不会触发当前子组件的监控事件,期间不做返回值判断。

11摘要

至此,$dispatch和$broadcast的讲解结束。也许每个人都已经知道为什么2.0版本删除了这两个属性。首先,我们介绍一下官网的声明:

因为基于构件树结构的事件流模式很难理解,在构件结构扩展的过程中会变得越来越脆弱。这种事件真的不太好,我们也不想让开发商以后吃太多苦头。而且,$dispatch和$broadcast并没有解决兄弟组件之间的通信问题。

所以$dispatch和$broadcast确实有这样的问题。在前面的解释中不难发现,$dispatch主要是指从当前组件到父组件的事件流,在满足一定条件时会触发当前子组件的监控事件。$broadcast的功能是事件流将从当前组件流向子组件,当满足一定条件时将触发当前子组件的监控事件。也就是说,$dispatch和$broadcast主要解决的是父子组件和嵌套父子组件之间的通信,并没有解决兄弟组件之间的通信问题。另一方面,这样的事件流模式基于组件树结构。当业务变得越来越复杂时,这种模式会极其繁琐甚至混乱,难以维护,因此有望在Vue 2.0版本中去掉这两个API。

但是为什么三个UI库都封装了这样一种组件通信方式呢?我的猜测可能是通过父子级嵌套组件中的$dispatch和$broadcast来解决远程调用事件到父组件或子组件的问题,从而避免通过传递道具或使用refs调用组件实例方法的操作。这样,$dispatch和$broadcast就值得存在,但也不是一无是处。还是那句话:技术没有好坏,只有合适和不合适!

好了,这就是本文的全部内容。希望本文的内容对你的学习或工作有一定的参考价值。有问题可以留言交流。谢谢你的支持。

更多资讯
游戏推荐
更多+