在使用vue的过程中难免会用到vuex,但是很多时候我们只知道怎么用却不了解其内部运行机制。下面简单手写一下vuex的实现过程。简介Vuex是一种专门为Vue.js应用程序开发的状态管理模式。它集中存储应用所有组件的状态,并制定相应的规则,保证组件状态能够朝着可预测的方向变化。首先需要了解vuex的几个核心概念:State单状态树,唯一的数据源Mutation状态改变函数Action包含任意异步操作Getterstate导出一些状态,类似于计算属性Modulestore模块分段机制,store包含了以上概念的容器如果你对这些概念不清楚,可以看vuex官方进一步了解:https://vuex.vuejs.org/zh/vuex原理分析首先,vuex是一个插件-中,我们需要声明一个store类,还有一个install方法去挂载$store。store的具体实现过程:1.创建responsivestate,保存mutations、actions和getters。2.实现commit根据用户传入的类型执行对应的mutation。3.实现dispatch根据传入的类型生成相应的action,同时传递数据。4.实现getters,根据getters的定义,从state中获取数据。首先设计vuex的基础数据:importVuefrom'vue'importVuexfrom'./vuex'Vue.use(Vuex)exportdefaultnewVuex.Store({state:{counter:0,},mutations:{add(state){state.counter++}},actions:{//参数从哪里来add({commit}){//业务逻辑组合或异步setTimeout(()=>{commit('add')},1000);}},getters:{doubleCounter:state=>{returnstate.couter*2;},},modules:{}})1.store类的声明,install方法的实现。letVue;//声明Store类classStore{constructor(options={}){this._vm=newVue({//data中的值将是响应式data:{//相当于bus$$state:options.state}});}getstate(){//访问器使其只读returnthis._vm._data.$$state}setstate(v){console.error('请使用replaceState重置状态');}}functioninstall(_Vue){Vue=_Vue;Vue.mixin({beforeCreate(){if(this.$options.store){//this.$options是Vue实例的初始化选项Vue.prototype.$store=this.$options.store;}}});}exportdefault{Store,install};这里有两点值得注意。源码中的state利用了vue的data的responsiveness。使用访问器,将状态设置为只读属性。这里的double$definitionstate第一次来肯定有点迷惑,因为它是让Vue不做代理的。2.实现commit:根据用户传入的类型获取并执行对应的mutation类Store{constructor(options={}){//保存用户配置的mutationsoptionsthis._mutations=options.mutations||{}}commit(type,payload){//获取类型对应的突变constentry=this._mutations[type]if(!entry){console.error(`unknownmutationtype:${type}`);return}//将上下文指定为Store实例//将状态传递给突变entry(this.state,payload);entry(this.state,payload)}}这里entry是mutations中定义的add方法,payload是传入参数。3.实现动作:获取并执行对应的动作commit=functionboundCommit(type,payload){commit.call(store,type,payload)}this.dispatch=functionboundDispatch(type,payload){dispatch.call(store,type,payload)}}//调度,执行异步任务或复杂逻辑dispatch(type,payload){//1.获取动作constentry=this._actions[type]if(!entry){console.error('哦,没有这样的动作');返回;}//异步结果处理经常需要返回Promisereturnentry(this,payload)}}这里this绑定了dispatch和commit,必须绑定commitcontext,否则在action3中调用commit时可能会出问题.Implementationgetters:state的动态计算属性classStore{constructor(options){conststore=thisthis._wrappedGetters=options.getters//定义计算选项constcomputed={}this.getters={}Object.keys(this._wrappedGetters).forEach(键=>{//Getuser-definedgettersconstfn=store._wrappedGetters[key]//转换为computed可以使用无参数形式computed[key]=function(){returnfn(store.state)}//为getters定义只读属性Object.defineProperty(store.getters,key,{get:()=>store._vm[key]})})this._vm=newVue({//data中的值将是responsivedata:{$$state:options.state},//使用vue的computed属性computed})}这里看起来很复杂,仔细拆分一个个看,其实很简单这里值得注意的是store._vm[key]是响应式的,使用Object.defineProperty设置只读属性,这样store.getters[key]将随着store._vm[key]的变化而响应变化。这里的get可以理解为vue中的计算属性内容。最终效果
