最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 手撕Vuex---------Vuex实现原理分析

    正文概述 掘金(山竹回家了)   2021-02-07   457

    1.添加全局$store

    //外界调用vue.use会执行install,并且会在执行时会把Vue实例和可选参数传递过来
    const install = (Vue, options) => {
        // 给每一个Vue实例添加一个$store属性
        // vue中有一个名称叫做mixin的方法,这个方法会在创建每一个vue实例时执行
        // 所以可以通过mixin给每一个实例添加$store属性,mixin接收一个对象
        Vue.mixin({
            // 重写每一个vue实例的生命周期方法
            beforeCreate() {
                // Vue在创建实例的时候会先创建父组件,然后创建子组件
                // console.log(this.$options.name);
                // Root->App->Helloworld
                //如果是根组件,那么默认有store,所以只需要将store变成$store即可
                if (this.$options && this.$options.store) {
                    this.$store = this.$options.store
                } else {
                    // 如果不是根组件,默认没有store,将父亲的$store赋值给子代
                    this.$store = this.$parent.$store
                }
            }
        })
    }
    // 在Vuex中新增Store属性,这个属性的取值是一个类
    class Store {
        // 调用的时候会传递一个对象参数,也就是仓库
        constructor(options) {
            this.options = options
        }
    }
    
    //暴露
    export default {
        install,
        Store
    }
    

    2.实现共享数据

    //外界调用vue.use会执行install,并且会在执行时会把Vue实例和可选参数传递过来
    const install = (Vue, options) => {
        // 给每一个Vue实例添加一个$store属性
        // vue中有一个名称叫做mixin的方法,这个方法会在创建每一个vue实例时执行
        // 所以可以通过mixin给每一个实例添加$store属性,mixin接收一个对象
        Vue.mixin({
            // 重写每一个vue实例的生命周期方法
            beforeCreate() {
                // Vue在创建实例的时候会先创建父组件,然后创建子组件
                // console.log(this.$options.name);
                // Root->App->Helloworld
                //如果是根组件,那么默认有store,所以只需要将store变成$store即可
                if (this.$options && this.$options.store) {
                    this.$store = this.$options.store
                } else {
                    // 如果不是根组件,默认没有store,将父亲的$store赋值给子代
                    this.$store = this.$parent.$store
                }
            }
        })
    }
    // 在Vuex中新增Store属性,这个属性的取值是一个类
    class Store {
        // 调用的时候会传递一个对象参数,也就是仓库
        constructor(options) {
            // this.options = options
            // =============================更新==========================
            // 将创建Store时需要共享的数据添加到Store上面
            //这样将来就可以通过this.$store拿到这个Store
            // 既然能拿到这个Store, 就可以通过.state拿到需要共享的属性
            this.state = options.state
        }
    }
    
    //暴露
    export default {
        install,
        Store
    }
    

    效果 手撕Vuex---------Vuex实现原理分析

    3.实现getters方法

    //外界调用vue.use会执行install,并且会在执行时会把Vue实例和可选参数传递过来
    const install = (Vue, options) => {
        // 给每一个Vue实例添加一个$store属性
        // vue中有一个名称叫做mixin的方法,这个方法会在创建每一个vue实例时执行
        // 所以可以通过mixin给每一个实例添加$store属性,mixin接收一个对象
        Vue.mixin({
            // 重写每一个vue实例的生命周期方法
            beforeCreate() {
                // Vue在创建实例的时候会先创建父组件,然后创建子组件
                // console.log(this.$options.name);
                // Root->App->Helloworld
                //如果是根组件,那么默认有store,所以只需要将store变成$store即可
                if (this.$options && this.$options.store) {
                    this.$store = this.$options.store
                } else {
                    // 如果不是根组件,默认没有store,将父亲的$store赋值给子代
                    this.$store = this.$parent.$store
                }
            }
        })
    }
    // 在Vuex中新增Store属性,这个属性的取值是一个类
    class Store {
        // 调用的时候会传递一个对象参数,也就是仓库
        constructor(options) {
            // this.options = options
            // 将创建Store时需要共享的数据添加到Store上面
            //这样将来就可以通过this.$store拿到这个Store
            // 既然能拿到这个Store, 就可以通过.state拿到需要共享的属性
            this.state = options.state
            // 将传递进来的getters放到Store上
            this.initGetters(options)
        }
        initGetters(options) {
            // 1.拿到传递进来的getters
            let getters = options.getters || {}
            // 2.在Store上新增一个getters的属性
            this.getters = {}
            //3.遍历传递进来的getters中的方法添加到当前Store的getters上
            for (let key in getters) {
                //    console.log(key);
                Object.defineProperty(this.getters, key, {
                    get: () => {
                        return getters[key](this.state)
                    }
                })
            }
        }
    }
    
    //暴露
    export default {
        install,
        Store
    }
    

    效果 手撕Vuex---------Vuex实现原理分析

    4.实现mutation方法

    // =======================更新=============================
    import Vue from 'vue'
    //外界调用vue.use会执行install,并且会在执行时会把Vue实例和可选参数传递过来
    const install = (Vue, options) => {
        // 给每一个Vue实例添加一个$store属性
        // vue中有一个名称叫做mixin的方法,这个方法会在创建每一个vue实例时执行
        // 所以可以通过mixin给每一个实例添加$store属性,mixin接收一个对象
        Vue.mixin({
            // 重写每一个vue实例的生命周期方法
            beforeCreate() {
                // Vue在创建实例的时候会先创建父组件,然后创建子组件
                // console.log(this.$options.name);
                // Root->App->Helloworld
                //如果是根组件,那么默认有store,所以只需要将store变成$store即可
                if (this.$options && this.$options.store) {
                    this.$store = this.$options.store
                } else {
                    // 如果不是根组件,默认没有store,将父亲的$store赋值给子代
                    this.$store = this.$parent.$store
                }
            }
        })
    }
    // 在Vuex中新增Store属性,这个属性的取值是一个类
    class Store {
        // 调用的时候会传递一个对象参数,也就是仓库
        constructor(options) {
            // this.options = options
            // 将创建Store时需要共享的数据添加到Store上面
            //这样将来就可以通过this.$store拿到这个Store
            // 既然能拿到这个Store, 就可以通过.state拿到需要共享的属性
            // =================================更新=============================
            // 在vue中有个util的工具类,通过defineReactive 方法,可以快速将某个数据变成双向绑定
            //这个方法接收三个参数:给哪个对象添加属性,给指定对象添加什么属性,要给属性添加什么值
            Vue.util.defineReactive (this,'state',options.state)
            // 将传递进来的getters放到Store上
            this.initGetters(options)
            // =================================更新=============================
            // 将传递进来的mutations放到Store上
            this.initMutions(options)
        }
        // =================================更新=============================
        commit(type,payload){//'addNum',10
            this.mutations[type](payload)
        }
        initMutions(options){
            // 1.拿到传递进来的mutation
            let mutations = options.mutations || {}
            // 2.在Store上新增一个mutation的属性
            this.mutations = {}
            //3.遍历传递进来的mutation中的方法添加到当前Store的mutation上
            for(let key in mutations){
                this.mutations[key]=(payload)=>{//10
                    // mutations['addNum'](num,10)
                    mutations[key](this.state,payload)
                }
            }
        }
        initGetters(options) {
            // 1.拿到传递进来的getters
            let getters = options.getters || {}
            // 2.在Store上新增一个getters的属性
            this.getters = {}
            //3.遍历传递进来的getters中的方法添加到当前Store的getters上
            for (let key in getters) {
                //    console.log(key);
                Object.defineProperty(this.getters, key, {
                    get: () => {
                        return getters[key](this.state)
                    }
                })
            }
        }
    }
    
    //暴露
    export default {
        install,
        Store
    }
    

    效果 手撕Vuex---------Vuex实现原理分析

    5.实现actions方法

    import Vue from 'vue'
    //外界调用vue.use会执行install,并且会在执行时会把Vue实例和可选参数传递过来
    const install = (Vue, options) => {
        // 给每一个Vue实例添加一个$store属性
        // vue中有一个名称叫做mixin的方法,这个方法会在创建每一个vue实例时执行
        // 所以可以通过mixin给每一个实例添加$store属性,mixin接收一个对象
        Vue.mixin({
            // 重写每一个vue实例的生命周期方法
            beforeCreate() {
                // Vue在创建实例的时候会先创建父组件,然后创建子组件
                // console.log(this.$options.name);
                // Root->App->Helloworld
                //如果是根组件,那么默认有store,所以只需要将store变成$store即可
                if (this.$options && this.$options.store) {
                    this.$store = this.$options.store
                } else {
                    // 如果不是根组件,默认没有store,将父亲的$store赋值给子代
                    this.$store = this.$parent.$store
                }
            }
        })
    }
    // 在Vuex中新增Store属性,这个属性的取值是一个类
    class Store {
        // 调用的时候会传递一个对象参数,也就是仓库
        constructor(options) {
            // this.options = options
            // 将创建Store时需要共享的数据添加到Store上面
            //这样将来就可以通过this.$store拿到这个Store
            // 既然能拿到这个Store, 就可以通过.state拿到需要共享的属性
            // 在vue中有个util的工具类,通过defineReactive 方法,可以快速将某个数据变成双向绑定
            //这个方法接收三个参数:给哪个对象添加属性,给指定对象添加什么属性,要给属性添加什么值
            Vue.util.defineReactive (this,'state',options.state)
            // 将传递进来的getters放到Store上
            this.initGetters(options)
            // 将传递进来的mutations放到Store上
            this.initMutions(options)
            // =======================更新==================
             // 将传递进来的actions放到Store上
             this.initActions(options)
        }
        dispatch=(type,payload)=>{//asyncAddNum 10
            this.actions[type](payload)// this.actions['asyncAddNum'](10)
        }
        initActions(options){
             // 1.拿到传递进来的actions
             let actions = options.actions || {}
             // 2.在Store上新增一个actions的属性
             this.actions = {}
             //3.遍历传递进来的mutation中的方法添加到当前Store的actions上
             for(let key in actions){
                 this.actions[key]=(payload)=>{
                     actions[key](this,payload)//actions['asyncAddNum'](this,10)
                 }
             }
        }
        // ====================更新===============
        commit=(type,payload)=>{//'addNum',10
            this.mutations[type](payload)
        }
        initMutions(options){
            // 1.拿到传递进来的mutation
            let mutations = options.mutations || {}
            // 2.在Store上新增一个mutation的属性
            this.mutations = {}
            //3.遍历传递进来的mutation中的方法添加到当前Store的mutation上
            for(let key in mutations){
                this.mutations[key]=(payload)=>{//10
                    // mutations['addNum'](num,10)
                    mutations[key](this.state,payload)
                }
            }
        }
        initGetters(options) {
            // 1.拿到传递进来的getters
            let getters = options.getters || {}
            // 2.在Store上新增一个getters的属性
            this.getters = {}
            //3.遍历传递进来的getters中的方法添加到当前Store的getters上
            for (let key in getters) {
                //    console.log(key);
                Object.defineProperty(this.getters, key, {
                    get: () => {
                        return getters[key](this.state)
                    }
                })
            }
        }
    }
    
    //暴露
    export default {
        install,
        Store
    }
    

    效果 手撕Vuex---------Vuex实现原理分析

    6.模块化共享数据

    提取模块信息

    自定义vuex.js

    import Vue from 'vue'
    //外界调用vue.use会执行install,并且会在执行时会把Vue实例和可选参数传递过来
    const install = (Vue, options) => {
        // 给每一个Vue实例添加一个$store属性
        // vue中有一个名称叫做mixin的方法,这个方法会在创建每一个vue实例时执行
        // 所以可以通过mixin给每一个实例添加$store属性,mixin接收一个对象
        Vue.mixin({
            // 重写每一个vue实例的生命周期方法
            beforeCreate() {
                // Vue在创建实例的时候会先创建父组件,然后创建子组件
                // console.log(this.$options.name);
                // Root->App->Helloworld
                //如果是根组件,那么默认有store,所以只需要将store变成$store即可
                if (this.$options && this.$options.store) {
                    this.$store = this.$options.store
                } else {
                    // 如果不是根组件,默认没有store,将父亲的$store赋值给子代
                    this.$store = this.$parent.$store
                }
            }
        })
    }
    // ================================================更新===========================
    // 定义模块信息的类
    class ModuleCollection {
        constructor(rootModule) {
            // 独立的方法来格式化
            this.register([], rootModule)
        }
        register(arr, rootModule) {
            // console.log(arr);//["login", "account"]
            // console.log(rootModule.state);
            // console.log(rootModule);
            // 1.按照需要的格式创建模块
            let module = {
                _raw: rootModule,
                _state: rootModule.state,
                _children: {}
            }
            //2.保存模块信息
            // 判断是根模块还是子模块
            if (arr.length == 0) {
                this.root = module//保存根模块
            } else {
                //保存子模块
                // this.root._children[arr[arr.length-1]]=module
                // let testArr= ["login", "account"]
                // let res=testArr.splice(0,testArr.length-1)
            //     // console.log(res);
              let parent=  arr.splice(0, arr.length - 1).reduce((root, currentKey) => {
                    return root._children[currentKey]
                }, this.root)
                parent._children[arr[arr.length-1]]=module
            } // 3.处理子模块,遍历跟模块中的modules
            for (let childrenModuleName in rootModule.modules) {
                let childrenModule = rootModule.modules[childrenModuleName]
                // console.log(childrenModule);
                // 开始递归,将子模块格式处理好后添加到children
                // concat() 方法用于连接两个或多个数组。
                this.register(arr.concat(childrenModuleName), childrenModule)
            }
        }
    }
    // 在Vuex中新增Store属性,这个属性的取值是一个类
    class Store {
        // 调用的时候会传递一个对象参数,也就是仓库
        constructor(options) {
            // this.options = options
            // 将创建Store时需要共享的数据添加到Store上面
            //这样将来就可以通过this.$store拿到这个Store
            // 既然能拿到这个Store, 就可以通过.state拿到需要共享的属性
            // 在vue中有个util的工具类,通过defineReactive 方法,可以快速将某个数据变成双向绑定
            //这个方法接收三个参数:给哪个对象添加属性,给指定对象添加什么属性,要给属性添加什么值
            Vue.util.defineReactive(this, 'state', options.state)
            // 将传递进来的getters放到Store上
            this.initGetters(options)
            // 将传递进来的mutations放到Store上
            this.initMutions(options)
            // 将传递进来的actions放到Store上
            this.initActions(options)
            //  ==================更新====================================
            //提取模块信息
            this.modules = new ModuleCollection(options)
            // console.log(this.modules);
        }
        dispatch = (type, payload) => {//asyncAddNum 10
            this.actions[type](payload)// this.actions['asyncAddNum'](10)
        }
        initActions(options) {
            // 1.拿到传递进来的actions
            let actions = options.actions || {}
            // 2.在Store上新增一个actions的属性
            this.actions = {}
            //3.遍历传递进来的mutation中的方法添加到当前Store的actions上
            for (let key in actions) {
                this.actions[key] = (payload) => {
                    actions[key](this, payload)//actions['asyncAddNum'](this,10)
                }
            }
        }
        commit = (type, payload) => {//'addNum',10
            this.mutations[type](payload)
        }
        initMutions(options) {
            // 1.拿到传递进来的mutation
            let mutations = options.mutations || {}
            // 2.在Store上新增一个mutation的属性
            this.mutations = {}
            //3.遍历传递进来的mutation中的方法添加到当前Store的mutation上
            for (let key in mutations) {
                this.mutations[key] = (payload) => {//10
                    // mutations['addNum'](num,10)
                    mutations[key](this.state, payload)
                }
            }
        }
        initGetters(options) {
            // 1.拿到传递进来的getters
            let getters = options.getters || {}
            // 2.在Store上新增一个getters的属性
            this.getters = {}
            //3.遍历传递进来的getters中的方法添加到当前Store的getters上
            for (let key in getters) {
                //    console.log(key);
                Object.defineProperty(this.getters, key, {
                    get: () => {
                        return getters[key](this.state)
                    }
                })
            }
        }
    }
    
    //暴露
    export default {
        install,
        Store
    }
    

    index.js

    import Vue from 'vue'
    import Suex from './Suex'
    
    // ===============================更新=========================
    // =====================要注意顺序,否则报错==========================
    Vue.use(Suex)
    let login={
      //用于保存共享数据
      state: {
        name: '杀生丸',
        num: 0
      },
      mutations: {
      },
      //用于异步修改共享数据
      actions: {
      },
      //用于模块化共享数据
      modules: {
      },
      getters: {
      }
    }
    let account={
      //用于保存共享数据
      state: {
        name: '胖虎',
        num: 0
      },
      mutations: {
      },
      //用于异步修改共享数据
      actions: {
      },
      //用于模块化共享数据
      modules: {
        login
      },
      getters: {
      }
    }
    
    export default new Suex.Store({
      //用于保存共享数据
      state: {
        name: '山竹回家了',
        num: 0
      },
      mutations: {
        addNum(state, payload) {
          state.num += payload
        }
      },
      //用于异步修改共享数据
      actions: {
        asyncAddNum({commit},payload){
          setTimeout(()=>{
            commit('addNum',payload)
          },3000)
        }
      },
      //用于模块化共享数据
      modules: {
        account
      },
      getters: {
        // 相当于vuex的计算属性
        myName(state) {
          return state.name + '111'
        },
      }
    })
    
    

    7.安装模块数据

    import Vue from 'vue'
    //外界调用vue.use会执行install,并且会在执行时会把Vue实例和可选参数传递过来
    const install = (Vue, options) => {
        // 给每一个Vue实例添加一个$store属性
        // vue中有一个名称叫做mixin的方法,这个方法会在创建每一个vue实例时执行
        // 所以可以通过mixin给每一个实例添加$store属性,mixin接收一个对象
        Vue.mixin({
            // 重写每一个vue实例的生命周期方法
            beforeCreate() {
                // Vue在创建实例的时候会先创建父组件,然后创建子组件
                // console.log(this.$options.name);
                // Root->App->Helloworld
                //如果是根组件,那么默认有store,所以只需要将store变成$store即可
                if (this.$options && this.$options.store) {
                    this.$store = this.$options.store
                } else {
                    // 如果不是根组件,默认没有store,将父亲的$store赋值给子代
                    this.$store = this.$parent.$store
                }
            }
        })
    }
    // 定义模块信息的类
    class ModuleCollection {
        constructor(rootModule) {
            // 独立的方法来格式化
            this.register([], rootModule)
        }
        register(arr, rootModule) {
            // console.log(arr);//["login", "account"]
            // console.log(rootModule.state);
            // console.log(rootModule);
            // 1.按照需要的格式创建模块
            let module = {
                _raw: rootModule,
                _state: rootModule.state,
                _children: {}
            }
            //2.保存模块信息
            // 判断是根模块还是子模块
            if (arr.length == 0) {
                this.root = module//保存根模块
            } else {
                //保存子模块
                // this.root._children[arr[arr.length-1]]=module
                // let testArr= ["login", "account"]
                // let res=testArr.splice(0,testArr.length-1)
                //     // console.log(res);
                let parent = arr.splice(0, arr.length - 1).reduce((root, currentKey) => {
                    return root._children[currentKey]
                }, this.root)
                parent._children[arr[arr.length - 1]] = module
            } // 3.处理子模块,遍历跟模块中的modules
            for (let childrenModuleName in rootModule.modules) {
                let childrenModule = rootModule.modules[childrenModuleName]
                // console.log(childrenModule);
                // 开始递归,将子模块格式处理好后添加到children
                // concat() 方法用于连接两个或多个数组。
                this.register(arr.concat(childrenModuleName), childrenModule)
            }
        }
    }
    // 在Vuex中新增Store属性,这个属性的取值是一个类
    class Store {
        // 调用的时候会传递一个对象参数,也就是仓库
        constructor(options) {
            // this.options = options
            // 将创建Store时需要共享的数据添加到Store上面
            //这样将来就可以通过this.$store拿到这个Store
            // 既然能拿到这个Store, 就可以通过.state拿到需要共享的属性
            // 在vue中有个util的工具类,通过defineReactive 方法,可以快速将某个数据变成双向绑定
            //这个方法接收三个参数:给哪个对象添加属性,给指定对象添加什么属性,要给属性添加什么值
            // =========================================这里已经安装了根模块的数据,=========================
            Vue.util.defineReactive(this, 'state', options.state)
            // 将传递进来的getters放到Store上
            this.initGetters(options)
            // 将传递进来的mutations放到Store上
            this.initMutions(options)
            // 将传递进来的actions放到Store上
            this.initActions(options)
            //提取模块信息
            this.modules = new ModuleCollection(options)
            // console.log(this.modules);
            // ========================================这里只需要将子模块数据安装==============================
            // 安装子模块数据
            this.initModules([], this.modules.root)
        }
        initModules(arr, rootModule) {
            // 用空数组判断是根模块还是子模块,如果是子模块就将数据安装到this.state上
            if (arr.length > 0) {
                let parent = arr.splice(0, arr.length - 1).reduce((state, currentKey) => {
                    // console.log(state[currentKey]);
                    return state[currentKey]
                }, this.state)
                // console.log(parent);
                // 哪一个对象添加属性,添加什么属性,什么数据
                Vue.set(parent,arr[arr.length-1],rootModule._state)
            }
            //如果当前不是子模块,那么需要从根模块中取出子模块的信息来安装
            for (let childrenModuleName in rootModule._children) {
                let childrenModule = rootModule._children[childrenModuleName]
                // console.log(childrenModule);
                this.initModules(arr.concat(childrenModuleName), childrenModule)
            }
        }
        dispatch = (type, payload) => {//asyncAddNum 10
            this.actions[type](payload)// this.actions['asyncAddNum'](10)
        }
        initActions(options) {
            // 1.拿到传递进来的actions
            let actions = options.actions || {}
            // 2.在Store上新增一个actions的属性
            this.actions = {}
            //3.遍历传递进来的mutation中的方法添加到当前Store的actions上
            for (let key in actions) {
                this.actions[key] = (payload) => {
                    actions[key](this, payload)//actions['asyncAddNum'](this,10)
                }
            }
        }
        commit = (type, payload) => {//'addNum',10
            this.mutations[type](payload)
        }
        initMutions(options) {
            // 1.拿到传递进来的mutation
            let mutations = options.mutations || {}
            // 2.在Store上新增一个mutation的属性
            this.mutations = {}
            //3.遍历传递进来的mutation中的方法添加到当前Store的mutation上
            for (let key in mutations) {
                this.mutations[key] = (payload) => {//10
                    // mutations['addNum'](num,10)
                    mutations[key](this.state, payload)
                }
            }
        }
        initGetters(options) {
            // 1.拿到传递进来的getters
            let getters = options.getters || {}
            // 2.在Store上新增一个getters的属性
            this.getters = {}
            //3.遍历传递进来的getters中的方法添加到当前Store的getters上
            for (let key in getters) {
                //    console.log(key);
                Object.defineProperty(this.getters, key, {
                    get: () => {
                        return getters[key](this.state)
                    }
                })
            }
        }
    }
    
    //暴露
    export default {
        install,
        Store
    }
    

    效果 手撕Vuex---------Vuex实现原理分析

    8.安装模块方法

    import Vue from 'vue'
    //外界调用vue.use会执行install,并且会在执行时会把Vue实例和可选参数传递过来
    const install = (Vue, options) => {
        // 给每一个Vue实例添加一个$store属性
        // vue中有一个名称叫做mixin的方法,这个方法会在创建每一个vue实例时执行
        // 所以可以通过mixin给每一个实例添加$store属性,mixin接收一个对象
        Vue.mixin({
            // 重写每一个vue实例的生命周期方法
            beforeCreate() {
                // Vue在创建实例的时候会先创建父组件,然后创建子组件
                // console.log(this.$options.name);
                // Root->App->Helloworld
                //如果是根组件,那么默认有store,所以只需要将store变成$store即可
                if (this.$options && this.$options.store) {
                    this.$store = this.$options.store
                } else {
                    // 如果不是根组件,默认没有store,将父亲的$store赋值给子代
                    this.$store = this.$parent.$store
                }
            }
        })
    }
    // 定义模块信息的类
    class ModuleCollection {
        constructor(rootModule) {
            // 独立的方法来格式化
            this.register([], rootModule)
        }
        register(arr, rootModule) {
            // console.log(arr);//["login", "account"]
            // console.log(rootModule.state);
            // console.log(rootModule);
            // 1.按照需要的格式创建模块
            let module = {
                _raw: rootModule,
                _state: rootModule.state,
                _children: {}
            }
            //2.保存模块信息
            // 判断是根模块还是子模块
            if (arr.length == 0) {
                this.root = module//保存根模块
            } else {
                //保存子模块
                // this.root._children[arr[arr.length-1]]=module
                // let testArr= ["login", "account"]
                // let res=testArr.splice(0,testArr.length-1)
                //     // console.log(res);
                let parent = arr.splice(0, arr.length - 1).reduce((root, currentKey) => {
                    return root._children[currentKey]
                }, this.root)
                parent._children[arr[arr.length - 1]] = module
            } // 3.处理子模块,遍历跟模块中的modules
            for (let childrenModuleName in rootModule.modules) {
                let childrenModule = rootModule.modules[childrenModuleName]
                // console.log(childrenModule);
                // 开始递归,将子模块格式处理好后添加到children
                // concat() 方法用于连接两个或多个数组。
                this.register(arr.concat(childrenModuleName), childrenModule)
            }
        }
    }
    // 在Vuex中新增Store属性,这个属性的取值是一个类
    class Store {
        // 调用的时候会传递一个对象参数,也就是仓库
        constructor(options) {
            // this.options = options
            // 将创建Store时需要共享的数据添加到Store上面
            //这样将来就可以通过this.$store拿到这个Store
            // 既然能拿到这个Store, 就可以通过.state拿到需要共享的属性
            // 在vue中有个util的工具类,通过defineReactive 方法,可以快速将某个数据变成双向绑定
            //这个方法接收三个参数:给哪个对象添加属性,给指定对象添加什么属性,要给属性添加什么值
            Vue.util.defineReactive(this, 'state', options.state)
    
            //提取模块信息
            this.modules = new ModuleCollection(options)
            // console.log(this.modules);
            // 安装子模块数据
            this.initModules([], this.modules.root)
        }
        initModules(arr, rootModule) {
            // 用空数组判断是根模块还是子模块,如果是子模块就将数据安装到this.state上
            if (arr.length > 0) {
                let parent = arr.splice(0, arr.length - 1).reduce((state, currentKey) => {
                    // console.log(state[currentKey]);
                    return state[currentKey]
                }, this.state)
                // console.log(parent);
                // 哪一个对象添加属性,添加什么属性,什么数据
                Vue.set(parent, arr[arr.length - 1], rootModule._state)
            }
            // =======================更新=========================
            // 将传递进来的getters放到Store上
            this.initGetters(rootModule._raw)
            // 将传递进来的mutations放到Store上
            this.initMutions(rootModule._raw)
            // 将传递进来的actions放到Store上
            this.initActions(rootModule._raw)
            //如果当前不是子模块,那么需要从根模块中取出子模块的信息来安装
            for (let childrenModuleName in rootModule._children) {
                let childrenModule = rootModule._children[childrenModuleName]
                // console.log(childrenModule);
                this.initModules(arr.concat(childrenModuleName), childrenModule)
            }
        }
        dispatch = (type, payload) => {//asyncAddNum 10
            // =======================更新=========================
            this.actions[type].forEach(fn => fn(payload))// this.actions['asyncAddNum'](10)
        }
        initActions(options) {
            // 1.拿到传递进来的actions
            let actions = options.actions || {}
            // 2.在Store上新增一个actions的属性
            // =======================更新=========================
            this.actions = this.actions || {}
            //3.遍历传递进来的mutation中的方法添加到当前Store的actions上
            for (let key in actions) {
                // =======================更新=========================
                this.actions[key] = this.actions[key] || []
                this.actions[key].push((payload) => {
                    actions[key](this, payload)//actions['asyncAddNum'](this,10)
                })
            }
        }
        commit = (type, payload) => {//'addNum',10
            this.mutations[type].forEach(fn => fn(payload))
        }
        initMutions(options) {
            // 1.拿到传递进来的mutation
            let mutations = options.mutations || {}
            // 2.在Store上新增一个mutation的属性
            // =======================更新=========================
            this.mutations = this.mutations || {}
            //3.遍历传递进来的mutation中的方法添加到当前Store的mutation上
            for (let key in mutations) {
                // =======================更新=========================
                this.mutations[key] = this.mutations[key] || []
                this.mutations[key].push((payload) => {//10
                    // mutations['addNum'](num,10)
                    mutations[key](options.state, payload)
                })
            }
        }
        initGetters(options) {
            // 1.拿到传递进来的getters
            let getters = options.getters || {}
            // 2.在Store上新增一个getters的属性
            // =======================更新=========================
            this.getters = this.getters || {}
            //3.遍历传递进来的getters中的方法添加到当前Store的getters上
            for (let key in getters) {
                //    console.log(key);
                Object.defineProperty(this.getters, key, {
                    get: () => {
                        // =======================更新=========================
                        return getters[key](options.state)
                    }
                })
            }
        }
    }
    
    //暴露
    export default {
        install,
        Store
    }
    

    效果
    手撕Vuex---------Vuex实现原理分析


    起源地下载网 » 手撕Vuex---------Vuex实现原理分析

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元