vuex 插件原理解析

176 阅读1分钟

vuex 插件原理解析

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

状态自管理应用包含以下几个部分:

  • state,驱动应用的数据源;
  • view,以声明方式将 state 映射到视图;
  • actions,响应在 view 上的用户输入导致的状态变化。

vuex 核心概念:

  • state 是状态、数据
  • 使用 mutations 函数更改状态
  • 使用 actions 做异步处理
  • 使用 getters 做进一步 state 处理
  • 将 store 分成模块 modules 做模块化管理

一、 实现 Store 类

  1. 在 外面使用 new Vuex.Store 时会传入一个对象,对象里会有 state、mutations、getters、actions、modules 等对象属性;
  2. constructor 分别保存传入的这些参数对象,如下所示:
class Store {
    constructor(options) {
        this._mutations = options.mutations
        this._actions = options.actions
        this._wrappedGetters = options.getters
        this.getters = {}
    }
}
  1. 实现 state 的响应式
    用 new Vue 的方式实现响应式
class Store {
    constructor(options) {
        *省略*
        this._vm = new _Vue({
            data: {
                // 用 $$state 声明方式 防止外面用_vm._data直接访问
                $$state: options.state,
            },
            computed
        })
    }
    // 此处用 get 方式返回响应式对象
    get state() {
        return this._vm._data.$$state
    }
}
  1. 实现 getters 响应式
class Store {
    constructor(options) {
        *省略*
        this._wrappedGetters = options.getters
        this.getters = {}

        const store = this
        const computed = {}

        // 遍历getters对象下的每一个方法
        Object.keys(this._wrappedGetters).forEach(key => {
            const fn = store._wrappedGetters[key]
            // 把getters下的每一个方法用函数包装一下并返回执行结果赋值给计算属性
            computed[key] = function() {
                return fn(store.state)
            }
            // 设置store.getters的key的访问器属性,这样就可以通过$store.getters.aaa访问
            // 获取的时store实例上对应的值
            Object.defineProperty(store.getters, key, {
                get: () => store._vm[key]
            })
        })
    }
}
  1. 实现 commit 方法
commit(type, payload) {
    const mutation = this._mutations[type]
    if (!mutation || typeof mutation !== 'function') {
        return new Error('UnKnown is' + type)
    }
    mutation(this.state, payload)
}
  1. 实现 dispatch 方法
dispatch(type, payload) {
    const action = this._actions[type]
    if (!action || typeof action !== 'function') {
        return new Error('UnKnown is' + type)
    }
    action(this, payload)
}

二、 实现 install 函数

  1. 创建一个当前模块用的 let _Vue 对象, 在 install 方法被调用时会传入 Vue 对象 并 赋值给 _Vue;
  2. install 函数会在外面 Vue.use(Vuex) 调用执行
  3. install 函数里用全局混入函数 Vue.mixin,在 beforeCreate 钩子函数里挂载 $store;
  4. 当前Vuex实例会比 Vue实例早执行,所有要在mixin里做个全局混入,等main.js函数里的new Vue 执行完成后才能拿到 new Vuex.Store 的 实例 store,最后挂载到Vue的原型上 Vue.prototype.$store

_Vue, install, $store 的实现:

function install(Vue) {
    _Vue = Vue

    Vue.mixin({
        beforeCreate() {
            if (this.$options.store) {
                Vue.prototype.$store = this.$options.store
            }
        }
    })
}

三、 最后导出导出 export default { Store,install }