橙晨燕

vuePress-theme-reco Visionwuwu    2020 - 2021
橙晨燕 橙晨燕

Choose mode

  • dark
  • auto
  • light
主页
分类
  • 大学课程
  • 前端
  • 力扣算法
  • 随笔
标签
时间线
收藏集
  • 爱看的书
  • 爱追的剧
其他
  • 每日壹题 📚
  • CET-4 🛰️
  • 技术文档 📖
  • 收藏文章 📮
  • 项目展示 🚀
  • 项目总结 📝
  • 工具箱 📦

    • 图片压缩
    • 阿里云
    • 腾讯云
    • 掘金
    • CSDN
关于我
GitHub
author-avatar

Visionwuwu

25

文章

8

标签

主页
分类
  • 大学课程
  • 前端
  • 力扣算法
  • 随笔
标签
时间线
收藏集
  • 爱看的书
  • 爱追的剧
其他
  • 每日壹题 📚
  • CET-4 🛰️
  • 技术文档 📖
  • 收藏文章 📮
  • 项目展示 🚀
  • 项目总结 📝
  • 工具箱 📦

    • 图片压缩
    • 阿里云
    • 腾讯云
    • 掘金
    • CSDN
关于我
GitHub
  • 开始
  • JavaScript

  • Vue

    • 简易版vue2.0的mvvm实现
    • vuex源码实现
      • vuex源码第一版
      • vuex模块化实现
      • 在Store类中添加一个registerModule方法,用于动态添加模块
      • 我们还可以为vuex内部实现添加插件的功能
  • React

vuex源码实现

vuePress-theme-reco Visionwuwu    2020 - 2021

vuex源码实现


Visionwuwu 2020-05-28 vuex

  • vuex源码第一版
  • vuex模块化实现
  • 在Store类中添加一个registerModule方法,用于动态添加模块
  • 我们还可以为vuex内部实现添加插件的功能

# vuex源码第一版

let Vue;
let forEach = (obj, cb = false)=>{
    if(!obj) return;
    Object.keys(obj).forEach(key =>{
        cb && cb(key, obj[key])
    })
}
class Store{
    constructor(options){
        this.vm = new Vue({ // 将state收集起来作为依赖
            data: {
                state: options.state
            }
        });
        let getters = {};
        let mutations = {};
        let actions = {};
        // 定义getters对象重新定义属性,进行劫持数据
        forEach(options.getters, (key, value)=>{
            Object.defineProperty(getters, key, {
                get:()=>{
                    return value(this.state, this.getters)
                }
            })
        })
        forEach(options.mutations, (mutationName, value)=>{
            mutations[mutationName] = value;
        })
        forEach(options.actions, (actionName, value)=>{
            actions[actionName] = value;
        })
        this.getters = getters;
        this.mutations = mutations;
        this.actions = actions;
    }
    get state(){ // 类的属性访问器,当类的实列访问该属性是时会调用该函数
        return this.vm.state;
    }
    // es7写法
    commit = (mutationName, payload)=>{ // 唯一用于并同步修改state中的数据
        this.mutations[mutationName](this.state, payload)
    }
    dispatch(actionName, payload){
        this.actions[actionName](this, payload)
    }
}

function install(_Vue){
    Vue = _Vue;

    Vue.mixin({
        beforeCreate(){
            // 根组件
            if(this.$options.store){
                this.$store = this.$options.store
            } else{ // 父组件先于子组件渲染
                this.$store = this.$parent && this.$parent.$store
            }
        }
    })
}

export default {
    Store,
    install
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66

# vuex模块化实现

store.js里面数据

const store = new Vuex.Store({
    modules:{
        a:{
            state: {
                age: 10
            },
            mutations: {
                syncUpdateAge(state, payload){
                    state.age += payload
                }
            }
        },
        b:{
            state:{
                age: 20
            },
            mutations:{
                syncUpdateAge(state){
                    console.log('b跟新年龄')
                }
            },
            modules:{
                c: {
                    state: {
                        age: 30
                    },
                    mutations:{
                        syncUpdateAge(state){
                            console.log('c更新年龄')
                        }
                    }
                }
            }
        }
    },
    state: {
        age: 1,
        name: '张三'
    },
    getters: {
        getName(state){
            if(state.age > 20){
                return state.name
            }else{
                return '111'
            }
        }
    },
    mutations: {
        syncUpdateAge(state, payload){
            state.age += payload
        }
    },
    actions: {
        asyncUpdateAge({commit}, payload){
            setTimeout(_=>{
                commit('syncUpdateAge', 3)
            }, 1000)
        }
    }
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61

创建一个ModuleCollection进行模块化收集,格式化模块

class ModuleCollection{
    constructor(options){
        this.register([], options)
    }
    register(path, rootModule){
        let rawModule = {
            _rawModule: rootModule,
            _children: {},
            state: rootModule.state
        }
        // 添加根模块
        if(!this.root){
            this.root = rawModule
        }else {
            // 查找当前路径对应的父级模块
            let parentModule = path.slice(0, -1).reduce((root, currentPath)=>{
                return root._children[currentPath]
            }, this.root)
            parentModule._children[path[path.length - 1]] = rawModule;
        }

        if(rootModule.modules){
            // [a] 找到a模块,添加到对应父级模块下的_children下
            // [b] 找到b模块,添加到对应父级模块下的_children下
            // [b,c] 找到c模块,添加到对应父级模块下的_children下
            forEach(rootModule.modules, (moduleName, module)=>{
                this.register(path.concat(moduleName), module)
            })
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

将ModuleCollection格式好的模块化数据进行,安装到根模块中的state,和getters,mutations,actions中

// 模块安装
installModule(store, rootState, path, rootModule){
    // 遍历所有模块下的state安装到根模块下的state
    if(path.length > 0){
        // 遍历查找
        let parentModule = path.slice(0, -1).reduce((root, currentPath) => {
            return root[currentPath]
        }, rootState)
        // Vue.set(parentModule, path[path.length - 1], rootModule.state)
        parentModule[path[path.length - 1]] = rootModule.state
    }

    let getters = rootModule._rawModule.getters;
    if(getters){
        forEach(getters, (getterName, value)=>{
            Object.defineProperty(store.getters, getterName, {
                get(){
                    // 让getters使用自己的state
                    return value(rootModule.state) // 调用当前的函数
                }
            })
        })
    }

    let mutations = rootModule._rawModule.mutations
    if(mutations){
        forEach(mutations, (mutationName, value)=> {
            let mutations = store.mutations[mutationName] || []
            mutations.push((payload)=>{
                value(rootModule.state, payload)
                // 发布,通知所有订阅者
                this.subjects.forEach(fn=>{
                    fn({type: mutationName, payload}, store)
                })
            })
            store.mutations[mutationName] = mutations
        })
    }

    let actions = rootModule._rawModule.actions;
    if(actions) {
        forEach(actions, (actionName, value)=>{
            let actions = store.actions[actionName] || []
            actions.push((payload)=> {
                value(store, payload)
            })
            store.actions[actionName] = actions
        })
    }

    forEach(rootModule._children, (moduleName, module)=>{
        this.installModule(store, rootState, path.concat(moduleName), module)
    })
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

# 在Store类中添加一个registerModule方法,用于动态添加模块

// 注册模块
registerModule(path, module){
    if(!Array.isArray(path)){
        path = [path]
    }
    let rootModule = new ModuleCollection(module);
    this.installModule(this, this.state, path, rootModule.root)
}
1
2
3
4
5
6
7
8

# 我们还可以为vuex内部实现添加插件的功能

在创建Store类中options中添加插件配置项

// 设置用户信息到本地存储
const setUserInfoPlugin = (store)=>{
    store.subscribe((mutation, state)=>{
        const {type, payload} = mutation;
        console.log(type, payload)
    })
}
// 创建store实列
new Vuex.Store({
    plugins: [
       setUserInfoPlugin
    ]
})
1
2
3
4
5
6
7
8
9
10
11
12
13

主要代码实现

// 添加插件,订阅
options.plugins.forEach(fn=> fn(this))
// 添加订阅
subscribe(fn){
    this.subjects.push(fn)
}
// 发布,通知所有订阅者
this.subjects.forEach(fn=>{
    fn({type: mutationName, payload}, store)
})
1
2
3
4
5
6
7
8
9
10
在 GitHub 上编辑此页 !
最后一次更新: 5 个月前