浅谈Vue2.0父子组件间事件派发机制
从vue1.x过来的都知道,在vue2.0中,父子组件间事件通信的$dispatch和$broadcase被移除了。官方考虑是基于组件树结构的事件流方式实在是让人难以理解,并且在组件结构扩展的过程中会变得越来越脆落。特别是在组件层级比较深的情况下。通过广播和事件分发的机制,就显得比较混乱了。
官方在废除的同时,也为我们提供了替换方案,包括实例化一个空的vue实例,使用$emit反应子组件上的状态变化
1.使用$emit触发事件
helloWorld.vue作为父组件,dialogConfigVisible变量控制子组件弹框显示或隐藏。
configBox.vue作为子组件,假设为封装的公告弹窗。
在父组件中helloWorld.vue中
script
data(){ return{ dialogConfigVisible:true } } methods:{ changeConfigVisible(flag){ this.dialogConfigVisible=flag; } }
然后,在子组件configBox.vue中,主要在任意事件回调中,使用$emit来触发自定义的listenToConfig事件,后面还可以加上参数传给父组件。比如,在子组件弹窗上点击×关闭时,通知父组件helloWorld.vue我要关闭了,主要方便父组件改变相应状态变量,并传入false到自定义的事件中。
script
methods:{ dialogClose(){ this.show=false; this.$emit("listenToConfig",false) } }
在子組件中,主动触发listenToConfig事件,并传入参数false,告诉父组件helloWorld.vue对话框要关闭了。这里就可以避免父组件中的状态未变化,再次刷新页面的时候对话框会自动出现。
2.实例化一个空的vue实例bus
这里实例化一个bus空vue实例,主要为了统一管理子组件和父组件相互通信,通过bus作为媒介,首先新建一个bus.js文件,在里面新建一个对象,父组件为table.vue,子组件为tableColumn.vue
//bus.js importVuefrom"vue"; exportvarbus=newVue({ data:{ scrollY:false }, methods:{ updateScrollY(flag){ this.scrollY=flag; } } })
然后分别引入:
//table.vue
//tableColumn.vue
上面的父子组件中,父组件中利用bus注册监听事件getData,子组件中一旦有状态变化,就触发bus上对应的事件。
这种利用空实例的方式,相当于创建了一个事件中心,所以这种通信同样适用于非父子组件间的通信,
3.多级父子组件通信
有时,可能想要实现通信的两个组件不是直接的父子组件,而是祖父和孙子,或者是跨越了更多层级的父子组件
不可能由子组件一级一级的向上传递参数,来达到通信的目的,虽然现在我们理解的通信都是这样经过中转的。可以通过while等循环,不断向上遍历,直到找到目标父组件,就在对应的组件上触发事件。
下面就只element-ui实现的一个父子组件通信的mixins,对于组件同步有很大的作用。在element-ui的优点概述中也特意提到这个组件通信
functionbroadcast(componentName,eventName,params){ //向下遍历每个子节点,触发相应的向下广播的事件 this.$children.forEach(child=>{ varname=child.$options.componentName; if(name===componentName){ child.$emit.apply(child,[eventName].concat(params)); }else{ broadcast.apply(child,[componentName,eventName].concat([params])); } }); } exportdefault{ methods:{ //向上遍历父节点,来获取指定父节点,通过$emit在相应的组件中触发eventName事件 dispatch(componentName,eventName,params){ varparent=this.$parent||this.$root; varname=parent.$options.componentName; //上面的componentName需要在每个vue实例中额外配置自定义属性componentName, //可以简单替换成varname=parent.$options._componentTag; while(parent&&(!name||name!==componentName)){ parent=parent.$parent; if(parent){ name=parent.$options.componentName; } } if(parent){ parent.$emit.apply(parent,[eventName].concat(params)); } }, broadcast(componentName,eventName,params){ broadcast.call(this,componentName,eventName,params); } } };
首先定义两个嵌套的组件f1.vue和c1.vue,实例是:
然后,分别定义两个父子组件:
c2.vue
点击一下,就可以 importEmitterfrom"../mixins/emitter"; exportdefault{ name:"c2", mixins:[Emitter], componentName:'c2', methods:{ dispatchTest(){ this.dispatch('f1','listenerToC1',false); } } }
f1.vue
这样,就可以在子组件中点击按钮,触发listenerToC1事件,在父组件中监听到这个事件,
其实更$emit触发事件类似。不同之处在于,这里可以多级嵌套,不一定是直接的父子组件都可以触发到。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。