Vue中的情侣属性$dispatch和$broadcast详解

$dispatch 和 $broadcast 作为一对情侣 ?属性,在 Vue 1.0 中主要用来实现基于组件树结构的事件流通信 —— 通过向上或向下以冒泡的形式传递事件流,以实现嵌套父子组件的通信。但是由于其显功能缺陷,在 Vue 2.0 中就被移除了。虽然 Vue 官网已经不再支持使用 $dispatch 和 $broadcast 进行组件通信,但是在很多基于 Vue 的 UI 框架中都有对其的封装,包括 element-ui、iview 等等。

那么 $dispatch 和 $broadcast 到底是怎么工作,其底层又是怎么实现的呢?接下来,我们就详细的说一说!

01 $dispatch 详解

为了追根溯源,我们还是先去 Vue 1.0 的文档你观摩一下其概念吧!

概念:

Dispatch an event, first triggering it on the instance itself, and
then propagates upward along the parent chain. The propagation stops
when it triggers a parent event listener, unless that listener returns
true. Any additional arguments will be passed into the listener’s
callback function.

上面的一段英文定义来自 Vue 1.0 官方文档,其大致的意思是说:dispatch 是一个事件,首先会在自己实例本身上触发,然后沿父链向上传播。当它触发父组件上的事件侦听器时传播即会停止,除非该侦听器返回 true。 任何其他参数都将传递给侦听器的回调函数。

参数:

dispatch 会接收两中参数:event 是事件名称,[…args] 是触发事件时传递给回调函数的参数。

**例子:

// 创建一个 parent 组件
var parent = new Vue();
 
// 创建一个 child1 组件,其父组件指向 parent
var child1 = new Vue({ parent: parent });
 
// 创建一个 child2 组件,其父组件指向 child1
var child2 = new Vue({ parent: child1 });
 
// 在 parent 组件监听名为 test 的事件,并绑定了一个回调函数
parent.$on('test', function () {
 console.log('parent notified');
});
 
// 在 child1 组件监听名为 test 的事件,并绑定了一个回调函数
child1.$on('test', function () {
 console.log('child1 notified');
});
 
// 在 child2 组件监听名为 test 的事件,并绑定了一个回调函数
child2.$on('test', function () {
 console.log('child2 notified');
});

说到这里,parent、child1 和 child2 三个组件之间的关系可以展示成如下的关系图:

// 在 child2 组件中通过 dispatch 触发 test 事件
child2.$dispatch('test');
 
// 事件执行会输出如下结果
// -> "child2 notified"
// -> "child1 notified"

当执行 child2.$dispatch(‘test’); 时,首先会触发 child2 组件里面监听的 test 事件的回调函数,输出 ‘child2 notified’,根据上面官方文档的定义,事件会沿着组件关系链一直向上传递,然后传递到 child1 组件,触发监听事件输出 “child1 notified”,但是该侦听器没有返回 true,所以事件传递到此就结束了,最终的输出结果就只有 “child2 notified” 和 “child1 notified”。

Vue 1.0 官方实现

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

/**
 * Recursively propagate an event up the parent chain.
 * 递归地在父链上传播事件。
 * @param {String} event
 * @param {...*} additional arguments
 */
// $dispatch 方法是定义在 Vue 的 prototype 上的
// 接受一个字符串类型的事件名称
Vue.prototype.$dispatch = function (event) {
 // 首先执行 $emit 触发事件,将返回值保存在 shouldPropagate 中
 var shouldPropagate = this.$emit.apply(this, arguments)
  
 // 如果首次执行的 $emit 方法返回的值不是 true 就直接返回
 // 如果返回值不是 true 就说明组件逻辑不希望事件继续往父组件进行传递
 if (!shouldPropagate) return
  
 // 如果首次执行 $emit 方法返回值是 true 就获取当前组件的 parent 组件实例
 var parent = this.$parent
  
 // 将函数接受的参数转换成数组
 var args = toArray(arguments)
  
 // use object event to indicate non-source emit on parents
 // 根据传入的事件名称的参数组装成 object
 args[0] = { name: event, source: this }
  
 // 循环知道组件的父组件
 while (parent) {
 // 在父组件中执行 $emit 触发事件
 shouldPropagate = parent.$emit.apply(parent, args)
  
 // 如果父组件 $emit 返回的是 true 就继续递归祖父组件,否则就停止循环
 parent = shouldPropagate ? parent.$parent : null
 }
  
 // 最后返回当前组件实例
 return this
}

element-ui 实现

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

// 定义 dispatch 方法,接受三个参数,分别是:组件名称、将要触发的事件名称、回调函数传递的参数
dispatch(componentName, eventName, params) {
 // 获取基于当前组件的父组件实例,这里对父组件实例和根组件实例做了兼容处理
 var par
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值