Element的broadcast功能分析
功能简述
在Element中broadcast(事件广播)方法需要3个参数, componentName 组件名称, eventName 事件名,和 eventName 数据。
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的 eventName 的实现源码:
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)); } },
原文地址:https://www.cnblogs.com/xxcanghai/p/6382607.html