当前位置: 首页 > Web前端 > vue.js

手写简单Vuex

时间:2023-03-31 20:03:52 vue.js

前言本文适合使用过Vuex的人阅读,学习如何自己实现一个Vuex。基本骨架这是本项目的src/store/index.js文件,看一般vuex的使用importVuefrom'vue'importVuexfrom'./myvuex'//import自己写的vueximport*asgettersfrom'./getters'import*asactionsfrom'./actions'importstatefrom'./state'importmutationsfrom'./mutations'Vue.use(Vuex)//Vue.use(plugin)方法使用vuex插件//vuexexport一个类叫Store,传入一个对象作为参数exportdefaultnewVuex.Store({state,mutations,actions,getters,})Vue.use的使用方法:安装Vue.js插件。如果插件是对象,则必须提供安装方法。如果插件是一个函数,它将被用作安装方法。在调用install方法时,会将Vue作为参数传入。该方法的第一个参数是Vue构造函数,第二个参数是一个可选的选项对象。这个方法需要在调用newVue()之前调用。当同一个插件多次调用install方法时,该插件只会安装一次。即我们需要导出./myvuex.js中的install方法,同时导出一个类Store,所以第一步可以写代码:letVue=nullclassStore{constructor(options){}}functioninstall(_Vue){Vue=_Vue//上面的Store类需要能够获取到Vue}exportdefault{Store,install,}installmethod我们在使用vuex的时候,每个组件都有一个this.$store属性,其中包含state,mutations,actions,getters等等,所以我们还需要挂载一个$storeattribute在每个组件上,让每个组件都能获取到,这里我们使用Vue.mixin(mixin),用法如下:注册一个全局的mixin,影响注册后创建的每一个Vue实例。mixin可用于将自定义行为注入组件,这将影响随后创建的每个Vue实例。functioninstall(_Vue){Vue=_Vue//调用install方法时,会将Vue作为参数传入(上面的Store类需要使用Vue)//要实现各个组件,可以通过this调用$storeVue.mixin({beforeCreate(){//通过this.$options可以得到newVue({parameter})传递的参数if(this.$options&&this.$options.store){//证明this是根实例,也就是newVue生成的实例this.$store=this.$options.store}elseif(this.$parent&&this.$parent.$store){//子组件获取$store父组件的属性this.$store=this.$parent.$store}},})}state由于Vuex是基于Vue的响应式原则,所以如果我们要改变数据和刷新视图因为classStore{//options是Vuex.Store({})传入的参数constructor(options){//vuex的核心是借用vue的实例,因为vue的实例数据变化,视图会被刷新letvm=newVue({data:{state:options.state,},})//statethis.state=vm.state}}commit当我们使用vuex改变数据时,我们触发commit方法,使用方法如下:this.$store.commit('eventName','parameters');所以我们需要实现一个commit方法来处理Store构造函数传入的mutationsclassStore{constructor(options){//implementstate...//突变this.mutations={}//存储传入的突变letmutations=options.mutations||{}//循环出事件名进行处理(mutations[eventname]:executionmethod)Object.keys(mutations).forEach(key=>{this.mutations[key]=params=>{mutations[key].call(this,this.state,params)//将this固定为指向}})}commit=(key,params)=>{//key是要触发的事件的名称this.mutations[key](params)}}dispatch和上面的commit过程一样classStore{constructor(options={}){//...//actionsthis.actions={}letactions=options.actions||{}Object.keys(actions).forEach(key=>{this.actions[key]=params=>{actions[key].call(this,this,params)}})}dispatch=(type,payload)}=>{this.actions[type](payload)}}gettersgetters实际上是返回state的值,使用时放在computed属性中,每个getters都是函数的形式;getter需要双向绑定但不需要所有getter都双向绑定,只需要绑定项目中的事件使用的getter。这里使用了Object.defineProperty()方法,直接在一个对象上定义一个新的属性,或者修改一个对象已有的属性,并返回这个对象。classStore{constructor(options={}){//...//gettersthis.getters={}letgetters=options.getters||{}Object.keys(getters).forEach(key=>{Object.defineProperty(this.getters,key,{get:()=>{returngetters[key].call(this,this.state)},})})}}至此,我们可以使用自己的vuex完成一些基本的操作,但是只能以this.$store.xx的形式调用,所以需要重新实现方法。maphelper函数在使用maphelperfunction之前先讲mapState像这样:computed:{count(){returnthis.$store.state.count}}当map的computed属性名称与状态的子节点名称,将字符串数组传递给mapState。computed:{//使用对象扩展运算符将这个对象混入外部对象...mapState(['count'])}这里我们简单的只实现数组exportconstmapState=args=>{letobj={}args.forEach(item=>{obj[item]=function(){returnthis.$store.state[item]}})returnobj}后的几个map辅助函数类似mapGettersexportconstmapGetters=args=>{让obj={}args.forEach(item=>{obj[item]=function(){returnthis.$store.getters[item]}})returnobj}mapMutationsexportconstmapMutations=args=>{让obj={}args.forEach(item=>{obj[item]=function(params){returnthis.$store.commit(item,params)}})returnobj}mapActionsexportconstmapActions=args=>{letobj={}args.forEach(item=>{obj[item]=function(payload){returnthis.$store.dispatch(item,payload)}})returnobj}完整代码letVue=nullclassStore{constructor(options){//vuex的核心是借用vue的实例,因为实例datvue的a发生变化,视图会被刷新letvm=newVue({data:{state:options.state,},})//statethis.state=vm.state//mutationsthis.mutations={}//存储传入的mutationsletmutations=options.mutations||{}Object.keys(mutations).forEach(key=>{this.mutations[key]=params=>{mutations[key].call(this,this.state,params)}})//动作this.actions={}letactions=options.actions||{}Object.keys(actions).forEach(key=>{this.actions[key]=params=>{actions[key].call(this,this,params)}})//getterthis.getters={}让getters=options.getters||{}Object.keys(getters).forEach(key=>{Object.defineProperty(this.getters,key,{get:()=>{returngetters[key].call(this,this.state)},}})})}commit=(key,params)=>{this.mutations[key](params)}dispatch=(type,payload)=>{this.actions[type](payload)}}exportconstmapState=args=>{letobj={}args.forEach(item=>{obj[item]=function(){returnthis.$store.state[item]}})returnobj}exportconstmapGetters=复制代码args=>{letobj={}args.forEach(item=>{obj[item]=function(){returnthis.$store.getters[item]}})returnobj}exportconstmapMutations=args=>{让obj={}args.forEach(item=>{obj[item]=function(params){returnthis.$store.commit(item,params)}})returnobj}exportconstmapActions=args=>{让obj={}args.forEach(item=>{obj[item]=function(payload){returnthis.$store.dispatch(item,payload)}})returnobj}functioninstall(_Vue){Vue=_Vue//调用install方法时,会把Vue作为参数传入(上面的Store类需要用到Vue)//要实现各个组件,可以通过这个调用$storeVue.mixin({beforeCreate(){//通过this.$options可以得到newVue({parameter})传递的参数if(this.$options&&this.$options.store){//provethisthis是根实例,也就是newVue生成的实例this.$store=this.$options.store}elseif(this.$parent&&this.$parent.$store){//子组件得到父组件$store属性this.$store=this.$parent.$store}},})}exportdefault{Store,install,}整个项目源码地址:mini-vuexps:个人技术博文Github仓库,觉得不错欢迎star,给我点鼓励继续写~