详解如何实现一个简单的 vuex
首先我们需要知道为何要使用vuex。父子组件通信用prop和自定义事件可以搞定,简单的非父子组件通信用bus(一个空的Vue实例)。那么使用vuex就是为了解决复杂的非父子组件通信。
仅仅会使用vuex没什么,看过文档敲敲代码大家都会。难道你就不想知道vuex是如何实现的?!
抛开vuex的源码,我们先来想想如何实现一个简单的"vuex"。有多简单呢,我不要getter、mutation、action等,我只要state就行了。
非父子组件通信
在实现之前,我们得来温故一下bus的实现,借用官网的例子:
varbus=newVue() //触发组件A中的事件 bus.$emit('id-selected',1) //在组件B创建的钩子中监听事件 bus.$on('id-selected',function(id){ //... })
遥想当年,实例化后的bus不知放哪好,最后无奈将其放到了window下,一直window.bus的使用。虽然这样也没问题,但还是影响到了全局作用域。
突然的某一天,我发现可以挂载在vue的根实例下(从此告别window.bus),于是便有了:
varapp=newVue({ el:'#app', bus:bus }) //使用bus app.$options.bus //or this.$root.$options.bus
然后又发现了,bus其实不只是on事件才可以通信。其实bus是一个Vue实例,其中data是响应的。比如在app这个根实例下有两个非父子组件,都使用到了bus的data,那么它们是响应同步的。
varbus=newVue({ data:{ count:0 } })
以上,子组件a修改了count,如果子组件b有用到count,那么它就能响应到最新count的值。
说了这么多,你还没发现吗?这个不就是实现了非组件之间通信,vuex的state吗?!
封装bus
是的,把刚刚的bus封装一下,这个就是一个最简单的"vuex"(仅仅只有state的功能)。首先,我们将有一个根实例app,实例下有两个非父子组件childA和childB。
html代码的实现如下:
非父子组件的实现
然后是两个非父子组件和app的实现,子组件都使用到了bus的count,这里用store.state表示,跟vuex一致:
//待实现 conststore=newStore(Vue,{ state:{ count:0 } }) //子组件a constchildA={ template:'', methods:{ handleClick(){ this.$store.state.count+=1 } } } //子组件b constchildB={ template:'count:{{count}}', computed:{ count(){ returnthis.$store.state.count } } } newVue({ el:'#app', components:{ 'child-a':childA, 'child-b':childB }, store:store })
看到代码里还有一个Store待实现。所需要的参数,因为这里懒得用Vue.use(),所以直接将Vue作为参数传入以供使用,然后第二个参数跟我们使用vuex传入的参数一致。
Store的实现
接下来就是Store的实现,两步实现:
- 创建一个bus实例;
- 让子组件都能访问到this.$store。
第1步骤上面已经有了,第2步骤主要用到了Vue.mixin来全局混入,但仅仅只是找到有store的根实例并赋值Vue原型上的store,也能够让根实例app不用专门写mixins混入。
classStore{ constructor(Vue,options){ varbus=newVue({ data:{ state:options.state } }) this.install(Vue,bus) } install(Vue,bus){ Vue.mixin({ beforeCreate(){ if(this.$options.store){ Vue.prototype.$store=bus } } }) } }
实现的Store就是一个简单的"vuex",它拥有了vuex的state,足够让非父子组件之间进行简单通信。
在Store的构造函数里创建一个bus实例,并将其注入Vue的原型,实现了组件都能访问到this.$store即bus实例。this.$store就是一个Vue实例,所以访问了this.$store.state.count实际上就是访问到了data,从而实现了非父子组件之间的响应同步。全部源码参考这里。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。