vue 组件通信小结
prop + event
最常见的通信方式了,父组件通过prop
将数据传给子组件,子组件若想将数据回传给父组件,发送event
即可,如图:
举个例子:
father.component
1 | Vue.component('father', { |
child.component
1 | Vue.component('child', { |
这种方式适用于组件层级较浅的情况,因为不管是prop
还是event
都只能在父子组件之间传递,如果组件层级较深,这时传值就会很麻烦:
上面的图中,如果grandfather
想要把数据传给child
,就必须经过两次prop
的传递,反之child
传递数据给grandfather
也是一样。
这种做法还有一个更深的影响: 它使得组件之间的耦合变得严重,尤其是father
,它需要知道上下游组件的接口细节,这些都是在其关注点之外的,这让它变得不通用。
emitter mixin
此方法借鉴的是BUI的源码。prop + event
在传递event
时存在重复的繁琐细节:必须先把事件传给父组件,然后再由父组件传递给祖父组件,依次类推。父组件其实什么事情也没做,只是单纯的做个『传话员』。
如果可以直接指定任意祖先组件发送事件给其父组件,并带上想要的数据,就节省了很多多余的步骤。如图:
为了使每个组件都有这种能力,借助了vue
的mixin,它可以很方便的让组件复用功能。
具体代码
1 | const emitter = { |
缺点:这种方式只是缓解了prop + event
的症状,并没有从根本上解决,只能是一个临时的方案。
eventBus
在vue 官网上提到一种利用vue
当做事件总线来通信的方法,示意图如下:
事件总线可以贯穿整个组件树,每个组件都可以利用这根总线进行发布订阅。举个例子:
1 | var eventBus = new Vue(); |
来看看$emit
和$on
是怎么实现的:
Vue.prototype.$emit
1 | Vue.prototype.$emit = function(event) { |
Vue.prototype.$on
1 | Vue.prototype.$on = function(event, fn) { |
可以看到eventBus
其实就是利用观察者模式实现的。
这种方式依然针对的是事件传播,只不过现在它可以在任意组件之间传播事件,而不仅仅局限于具有祖先关系的组件。不过对于prop
传递繁琐的问题还是没有解决。
vuex
按照vuex 官网的解释:
把组件的共享状态抽取出来,以一个全局单例模式管理。在这种模式下,我们的组件树构成了一个巨大的“视图”,不管在树的哪个位置,任何组件都能获取状态或者触发行为。
它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
示意图:
使用vuex
很好的解决了上面几种方法的缺点:
- 祖先组件和子组件共享同一份数据,所有组件不再是层层传递
prop
,而是直接和vuex
打交道 - 也不在需要『逐层冒泡』
event
了,道理同上 - 很好的支持了关注点分离,每个组件只专注于处理关心的数据,不用管这些数据在哪里被用到,这样也提高了可复用性
唯一的缺点是在比较小的应用中会显得累赘,有点杀鸡用牛刀的感觉。