Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

实现一个vuex #46

Open
YIngChenIt opened this issue Jul 3, 2020 · 0 comments
Open

实现一个vuex #46

YIngChenIt opened this issue Jul 3, 2020 · 0 comments

Comments

@YIngChenIt
Copy link
Owner

实现一个vuex

实现一个mini-vuex

vuex就不做讲解和,核心就是一种递归方法的使用,这里就直接贴代码记录一下好了

let Vue
const forEach = (obj, cb) => {
    Object.keys(obj).forEach(key => {
        cb(key, obj[key])
    })
}
class ModuleCollection {
    constructor(options) {
        this.register([], options)
    }
    register(path, rootModule) {
        let newModule = {
            _raw: rootModule,
            _children: {},
            state: rootModule.state
        }
        if (path.length === 0) { //第一次执行
            this.root = newModule
        } else { //后面递归执行
            let parent = path.slice(0, -1).reduce((root, current) => {
                return root._children[current]
            }, this.root)
            parent._children[path[path.length - 1]] = newModule //取数组最后一个
        }
        if (rootModule.modules) {
            forEach(rootModule.modules, (moduleName, module) => {
                this.register(path.concat(moduleName), module)
            })
        }
    }
}

// 递归树 将结果挂载到 getters mutations actions
const installModule = (store, state, path, rootModule) => {
    if (path.length > 0) { //如果是子模块 需要把子模块的状态放到父模块上
        const parent = path.slice(0, -1).reduce((state, current) => {
           return state[current]
        }, state)
        Vue.set(parent, path[path.length - 1], rootModule.state)
    }
    // 先处理根模块的getters属性
    const getters = rootModule._raw.getters
    if (getters) {
        forEach(getters, (getterName, fn) => {
            Object.defineProperty(store.getters, getterName, {
                get: () => {
                    return fn(rootModule.state)
                }
            })
        })
    }
    const mutations = rootModule._raw.mutations
    if (mutations) {
        forEach(mutations, (mutationName, fn) => {
            let arr = store.mutations[mutationName] || (store.mutations[mutationName] = [])
            arr.push((payload) => {
                fn(rootModule.state, payload)
            })
        })
    }
    const actions = rootModule._raw.actions
    if (actions) {
        forEach(actions, (actionName, fn) => {
            let arr = store.actions[actionName] || (store.actions[actionName] = [])
            arr.push((payload) => {
                fn(store, payload)
            })
        })
    }

    forEach(rootModule._children, (moduleName, module) => {
        installModule(store, state, path.concat(moduleName), module)
    })
   
}
class Store {
    constructor(options) {
        this._s = new Vue({
            data: {
                state: options.state // 把state变成可以监控的对象 state改变可以触发视图更新
            }
        })
        this.getters = {}
        this.mutations = {}
        this.actions = {}
        // 收集所有模块
        this.modules = new ModuleCollection(options)
        // 安装模块
        installModule(this, this.state, [], this.modules.root)
    }
    commit = (type, payload) => {
        this.mutations[type].forEach((fn) => {
            fn(payload)
        })
    }
    dispatch = (type, payload) => {
        this.actions[type].forEach((fn) => {
            fn(payload)
        })
    }
    get state() {
        return this._s.state
    }
}

const install = _Vue => {
    Vue = _Vue
    Vue.mixin({
        beforeCreate() {
            if (this.$options && this.$options.store) {
                this.$store = this.$options.store
            } else {
                this.$store = this.$parent && this.$parent.$store
            }
        }
    })
}

export default {
    install,
    Store
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant