zoukankan      html  css  js  c++  java
  • vuex源码解析及简单实现

    vuex源码解析


    一、vuex的使用回顾

    //store/index.js
    import Vuex from "vuex"
    import Vue from "vue"
    Vue.use(Vuex)
    const store = new Vuex.Store({
            state: {
            count: 0
        }
        getters: {
            getCount: (state) => {return state.count}
        },
        mutations: {
            changeCount(state, payload) {
                state.count = payload
            },
       },
        actions: {
            addCount({commit},payload) {
            commit("changeCount",payload)
            }
        }
    })
    export default store
    
    //main.js
    import store from "./store"
    new Vue({
        el: "#app",
        store
    })
    

    二、逐句剖析vuex的使用

    1. vue.use( )

    import Vue from 'vue' 
    import Vuex from 'vuex'
    Vue.use(Vuex)
    

    解析: 上文中的 Vue.use(Vuex)会自动调用Vuex 这个对象的install方法, 并在install中传入 Vue 实例,来保证内外的Vue实例一致。你可以把Vue.use方法理解为:Vue.use = ( object ) => { object.install( this )}

    思考:故我们重构的 vuex 需要对外暴露一个install 方法

    2. new Vuex.Store( )

    const store = new Vuex.Store({
      state: {...},
      getters: {...},
      mutations: {...},
      actions: {...}
    })
    

    解析:new Vuex.Store()可以看出导入的Vuex包含着一个名为 Store的构造函数。

    思考:综合以上两点,我们可以推断出在 vuex 文件的导出内容大致为:

    export default {
        install: (vue)=> { 
            //todo 
        },
        Store: ({state,getters,actions,mutations})=> {
          //vuex的核心代码 
      }
    } 
    

    3. action

    const store = new Vuex.Store({
        actions: {
            addCount({commit},payload) {
            commit("changeCount",payload)
            }
        }
        state:{...},
        mutations: {...},
        getters: {...}
    }
    

    解析: 这种是官方推荐的结构写法,你也可以这么写

    addCount(context,payload) {
      context.commit("changeCount",payload)
    }
    

    解析: 第二种写法种的参数context是指上下文环境即这个store实例。上文中的第一种写法,既然可以从这个context中解构出commit方法,不难得出这个store实例包含commit方法


    三、刻画vuex 的大致结构

    class Store {
      constructor({state, getters, mutations, actions}) {
          //todo
      }
    }
    function install(vue){
      //todo
    }
    export default {
      Store,
      install
    }
    

    四、完成 install 方法

    思考: 在使用官方的vuex后, 我们在每个组件中都可以访问到this.$store, 可是我们在main.js中只是把store挂载到根实例中,按理说只有在根实例中才可以访问到store

    //main.js
    import store from "./store"
    new Vue({
        el: "#app",
        store
    })
    

    结论: 要在根实例中把store 赋值给$store,并且利用vue组件加载的先父后子原则,从根实例的子组件开始,每个组件都从父组件拿到$store,并将从父组件拿到的$store 赋值给自己的$store属性,从而实现每个组件都拥有$store属性,并且都指向同一个store实例

    let Vue
    let install = (_Vue) => {
        Vue = _Vue
      // 通过混入beforeCreate生命周期的钩子函数,使每个vue组件都挂载上store
        Vue.mixin({
            beforeCreate(){
            //this指向每个执行的 vue 组件
            //先判断当前的this是不是根实例,因为第一次执行只有根实例上的$options有store实例
                if(this.$options.store){
              //根实例
              this.$store = this.$options.store
                } else{
              //所以从根实例为一级组件开始,二级组件可以通过this.$parent 
              //拿到一级组件的store, 然后挂载到自己身上的$store
              //如此反复 每个组件都挂载上 $store
                    this.$store = this.$parent && this.$parent.$store
                }
            }
        })
    }
    export default install
    

    五、完成 Store 中的 state

    思考: store 中 state 的响应式是利用vue中data的响应式来实现的

    import install from './intsall.js'
    
    class Store {
        constructor({state,getters,mutations,actions}){
            this.vm = new Vue ({
                data: {
                    state
                }
            })
      }
    }
    
    export default {
        install,
        Store
    }
    

    六、完成 Store 中的 getters

    提示: 为了方便读者理解,接下来的内容我们会先列出用法,再展示功能实现代码

    getters: {
        getCount: (state) => {return state.count}
    },
    

    提示: 功能实现代码如下:

    class Store {
        /***** state code *****/
      constructor({state,getters,mutations,actions}){
        this.vm = new Vue ({
                data: {
                    state
                }
            })
      }
      
      /***** getters code ****/
      
      this.getters = {}
      for(let getterName in getters){
          // 利用Object.deineProperty 对this.getter 进行访问劫持
          Object.defineProperty(this.getters,getterName,{
          get: ()=>{
              //getter.getCount = (state) => {return state.count}
            return getter[getterName](this.vm.state)
          }
        })
      }
    }
    

    七、完成 Store 中的 mutations

    提示: 原生使用语法如下:

    mutations: {
        changeCount(state, payload) {
            state.count = payload
        },
    },
    

    提示: 功能实现代码如下:

    class Store {
        /***** state code *****/
      constructor({state,getters,mutations,actions}){
        this.vm = new Vue ({
                data: {
                    state
                }
            })
      }
      
      /***** mutations code ****/
      this.mutations = {}
      Object.keys(mutations).forEach( mutationName => {
        this.mutations[mutationName] = (newValue)=> {
          mutation[mutationName](this.vm.state,newValue)
        }
      })
    }
    

    八、完成 Store 中的 commit

    提示: 原生使用语法如下:

    addCount({commit},payload) {
        commit("changeCount",payload)
    }
    

    提示: 功能实现代码如下:

    class Store {
        /***** state code *****/
      constructor({state,getters,mutations,actions}){
        this.vm = new Vue ({
                data: {
                    state
                }
            })
      }
      
      /***** commit code ****/
      this.commit = (mutationName,newValue)=> {
            this.mutations[mutationName](newValue)
      }
    }
    

    九、完成 Store 中的 actions

    提示: 原生使用语法如下:

    actions:{
        addCount(context,payload) {
          context.commit("changeCount",payload)
        }
    }
    

    提示: 功能实现代码如下:

    class Store {
        /***** state code *****/
      constructor({state,getters,mutations,actions}){
        this.vm = new Vue ({
                data: {
                    state
                }
            })
      }
      
      /***** actions code ****/
      this.actions = {}
      Object.keys(actions).forEach(actionName => {
        this.actions[actionName] = (newValue)=> {
          actions[actionName](this, newValue)
        }
      })
    }
    
  • 相关阅读:
    Mono 1.1.16
    Minimum Profit 3.3.18a
    PenguinTV 1.90
    Beagle 0.2.7
    Bonfire 0.4.0
    wxDownload Fast 0.4.5
    Network Configurator 0.1.8
    VMware Server 1.0
    MonoDevelop 0.11
    GTKsopcast 0.2.8
  • 原文地址:https://www.cnblogs.com/fengtianxi001/p/14031268.html
Copyright © 2011-2022 走看看