Skip to content

手写简易版 Vuex

简易版 Vuex,直接引入也可以用

js
let Vue; // 插件全局使用

class Store {
  constructor(options) {
    // 保存用户定义的 mutations,actions,getters
    this._mutations = options.mutations;
    this._actions = options.actions;
    this._getters = options.getters;

    // 更正 this 指向
    this.commit = this.commit.bind(this);
    this.dispatch = this.dispatch.bind(this);

    // 实现 this.getters
    const computed = {};
    const store = this;
    this.getters = {};
    for (let key in this._getters) {
      // 用户定义的 getters 方法
      const fn = store._getters[key];
      // 无参数形式访问 this.getters.key
      computed[key] = () => fn(store.state);
      // 响应式只读属性
      Object.defineProperty(this.getters, key, {
        get: () => store._vm[key],
      });
    }

    // Vue 默认会把 data 遍历处理成响应式
    this._vm = new Vue({
      data: {
        $$state: options.state,
      },
      computed,
    });
  }

  // es6 get set
  get state() {
    return this._vm._data.$$state;
  }

  set state(v) {
    console.error('use replaceState to reset state');
  }

  commit(type, payload) {
    const entry = this._mutations[type];
    if (!entry) console.error('unknow mutations type');

    entry(this.state, payload);
  }

  dispatch(type, payload) {
    const entry = this._actions[type];
    if (!entry) console.error('unknow actions type');

    entry(this, payload);
  }
}

// Vue.use 方式 install.apply(this,[this,...])
function install(_Vue) {
  Vue = _Vue; //保存参入的 Vue,不用引入也能使用

  // 全局混入,挂载 $store,延迟下面逻辑到 store 被添加到 new vue 选项时才执行
  Vue.mixin({
    beforeCreate() {
      if (this.$options.store) {
        Vue.prototype.$store = this.$options.store;
      }
    },
  });
}

export default { Store, install };

基于 MIT 许可发布