1、接受参数:Vue 实现版本只会接受一个字符串类型的事件名称为参数,而 element-ui 实现的版本会接受三个参数,分别是:需要触发事件的组件名称、将要触发的事件名称、回调函数传递的参数;
2、实现功能:Vue 实现版本触发事件一直会顺着组件链向上进行传递,知道父组件中的侦听器没有返回 true,在这个期间所有的组件都会执行事件的响应,包括当前组件本身,而 element-ui 实现版本会不断的基于当前组件向父组件进行遍历,直至找到和接受的组件名称匹配,就会停止遍历,触发匹配组件中的监听事件。
10 $broadcast 详解
上面详细的说完 $dispatch 方法的实现和 Vue 实现版本与 element-ui 实现版本的区别,下面就该说说 $broadcast,毕竟他们是情侣属性嘛。
概念
Broadcast an event that propagates downward to all descendants of the current instance. Since the descendants expand into multiple sub-trees, the event propagation will follow many different “paths”. The propagation for each path will stop when a listener callback is fired along that path, unless the callback returns true.
broadcast 是一个事件,它向下传播到当前实例的所有后代。由于后代扩展为多个子树,事件传播将会遵循许多不同的“路径”。 除非回调返回 true,否则在沿该路径触发侦听器回调时,每个路径的传播将会停止。
参数
broadcast 会接收两中参数:event 是事件名称,[...args] 是触发事件时传递给回调函数的参数。
例子
// 创建 parent 组件实例 var parent = new Vue() // 创建 child1 组件实例,其父组件指向 parent var child1 = new Vue({ parent: parent }) // 创建 child2 组件实例,其父组件指向 parent var child2 = new Vue({ parent: parent }) // 创建 child3 组件实例,其父组件指向 child2 var child3 = new Vue({ parent: child2 }) // 在 child1 组件监听名为 test 的事件,并绑定了一个回调函数 child1.$on('test', function () { console.log('child1 notified') }) // 在 child2 组件监听名为 test 的事件,并绑定了一个回调函数 child2.$on('test', function () { console.log('child2 notified') }) // 在 child3 组件监听名为 test 的事件,并绑定了一个回调函数 child3.$on('test', function () { console.log('child3 notified') })
parent、child1、child2 和 child3 四个组件之间的关系可以展示成如下的关系图:
parent.$broadcast('test') // -> "child1 notified" // -> "child2 notified"
当执行 parent.$broadcast('test'); 时,事件流会以 parent 组件为起点向 parent 的子组件进行传递,根据事件绑定的顺序,虽然 parent 组件有两个同级的 child1 和 child2 ,但是事件流会先触发 child1 里面的绑定事件,此时会输出 "child1 notified",然后事件流到达 child2 组件,会触发 child2 组件中的绑定事件,输出 "child2 notified"。到这时,child2 组件中的侦听器并没有返回 true,所以事件传递到此就结束了,最终的输出结果就只有 "child1 notified" 和 "child2 notified"。
Vue 1.0 官方实现
在 Vue 1.0 版本中,$broadcast 实现的源码放在 /src/instance/api/events.js 文件中,代码很简单:
/** * Recursively broadcast an event to all children instances. * 递归地向所有子实例广播事件。 * @param {String|Object} event * @param {...*} additional arguments */ // $dispatch 方法是定义在 Vue 的 prototype 上的 // 接受一个事件 Vue.prototype.$broadcast = function (event) { // 获取传入事件的类型,判断是否为字符串 var isSource = typeof event === 'string' // 校正 event 的值,当接受 event 的类型为字符串时就直接使用,如果不是字符串就使用 event 上的 name 属性 event = isSource ? event : event.name // if no child has registered for this event, // then there's no need to broadcast. // 如果当前组件的子组件没有注册该事件,就直接返回,并不用 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 // 根据传入的事件名称的参数组装成 object args[0] = { name: event, source: this } } // 循环子组件 for (var i = 0, l = children.length; i < l; i++) { var child = children[i] // 在每个子组件中调用 $emit 触发事件 var shouldPropagate = child.$emit.apply(child, args) // 判断调用 $emit 返回的值是否为 true if (shouldPropagate) { // 如果调用 $emit 返回的值为 true,就递归孙子组件继续广播 child.$broadcast.apply(child, args) } } // 最后返回当前组件的实例 return this }
element-ui 实现
在 element-ui 中,$broadcast 实现的源码放在 /src/mixins/emitter.js 文件中,代码很简单: