我们知道通过全局事件总线的方法同样也能够实现任意组件间的通信,并且是依托于Vue的特性结合一些技巧实现的,并不需要第三方的支持,那么和全局事件总线相比Vuex和全局事件总线$bus的区别在哪里呢?我们下面来探讨一下:
总线和Vuex的共同点
组件能找到它们的原理如出一辙
Vuex状态管理是利用Store仓库进行管理,而事件总线是通过$bus绑定($on)和触发($emit)事件实现的。他们都使用了Vue 数据代理的这个重要的一个内置关系:VueComponent.prototype.__proto__ === Vue.prototype
我们来看看使用总线和使用状态管理的时候调用的的API就知道了
/*--------事件总线-----------*/
// 事件总线绑定事件
this.$bus.$on('handleAdd',handleAdd)
// 事件总线触发事件
this.$bus.$emit('handleAdd',this.count)
/*--------状态管理-----------*/
// 获取状态
this.$store.state.count
// 修改状态
this.$store.dispatch('increment',this.count)
this.$store.commit('INCREMENT',this.count)
我们可以看到调用他们的方式都是再组件中使用this获取到他们,这里的this就是指向当前的实例化组件(VueComponent),于是我们就可以通过VueComponent.prototype.__proto__ === Vue.prototype
这个内置关系知道数据最终是透过原型链找到的$bus/store,所以不管是Vuex还是总线,想要让全局能够获取到$bus/store他们的原理是一样的,那就是将他们创建在Vue的原型对象上。
const vm = new Vue({
render: h => h(App),
// 创建总线
beforeCreate() {
Vue.prototype.$bus = this
},
// 创建状态管理仓库
store,
}).$mount('#app')
我们可以看看Vue.use(Vuex)
他究竟帮我们做了什么
// Vuex提供了install属性,通过Vue.use(Vuex)来注册。
const install = function (Vue) {
Vue.mixin({
beforeCreate() {
if (this.$options.store) {
Vue.prototype.$store = this.$options.store
}
}
})
}
原理如出一辙!!
总线和Vuex的优缺点
是否使用第三方插件
事件总线不是三方库原来就有,而状态管理是一个强大且配套的第三方库。
事件总线不是三方库原来就有
章节开头时说过,全局事件总线是依托于Vue的特性结合一些技巧实现的,并不需要第三方的支持。他是依靠在Vue实例对象上的方法实现事件的绑定($on)、触发($emit)、解绑($off)
我们对总线的比喻常常就是公交车(bus[他有总线的意思]),或者是来完成组件间任意通信的工具人。它可以是组件的实例化对象(VueComponent)也可以是Vue实例本身(VM)【常用】,当$bus是Vue实例本身时就会在原型链上出现一个闭环就是$bus = Vue实例化对象。总之,全局事件总线是依靠Vue元编程的特性,经过经验总结形成的产物,没有使用到第三方插件(消息订阅和发布、状态管理都是三方库)。
状态管理是三方库
说到三方库,我们都说这个库能够活下来被大家fork的一般就是niubility的项目,他们一般都有着优雅、强大等等这些标签。状态管理就是这其中的一个。
状态管理作为三方库是符合Vue对渐进式框架这个定位的产物。我们用不用状态管理主要是看有没有必要杀猪用牛刀了。我们看看源码就知道为什么是牛刀了。
/**
* Extends interfaces in Vue.js
*/
import Vue, { ComponentOptions } from "vue";
import { Store } from "./index";
declare module "vue/types/options" {
interface ComponentOptions {
store?: Store;
}
}
declare module "vue/types/vue" {
interface Vue {
$store: Store;
}
}
我们不需要读懂源码,只需要明白他是将vue引入了,在实现上我们可以看到
Store仓库中Vue的实例化对象都出现了,所以我们心里面就明白了。Vuex其实是直接缔造了一个vm当作工具人(总线),并且将它封装的更加的优雅,作用更加的强大。Vuex是直接创建vue实例,而总线最多也只不过是在我们创建的vue实例上小打小闹,所以我们有时候在小项目中用上vuex就会有种杀猪用牛刀的调侃。
是否优雅
在经过前面的对比,想必读者都知道他们在实现上其实差不多,状态管理可能只是在总线的基础上做了优化罢了。没错这就是Vuex的核心竞争力——优雅。
熟练使用$bus事件总线的读者就会发现$bus其实还是有一些小小的问题不太优雅的
- 使用$on 绑定的事件名是不能重复的
$on 绑定数据之后,需要在组件销毁之前使用$off进行事件解绑
而Vuex是响应式的,和数据双向绑定的原理一样,使用了
getter
和setter
进行数据劫持,使用配置对象的形式来控制数据,所以当触发的事件名相同时,相同的名字对应的方法都会触发,也不需要对事件进行解绑,非常的优雅。
这些就是我总结的区别,如果有错误之处欢迎大家在评论区指正。
对象具有属性__proto__,可称为隐式原型,一个对象的隐式原型指向构造该对象的构造函数的原型,这也保证了实例能够访问在构造函数原型中定义的属性和方法。