手写自己的store

245 阅读1分钟

1、从项目中复制store文件夹,命名为kstore,再新建一个kvuex.js文件

// 1.声明一个插件
// 2.实现一个Store
//    实现响应式state属性
//    实现两个方法commit()/dispatch()
let Vue;
class Store {
  constructor(options) {
    // 1.保存选项
    this._mutations = options.mutations || {};
    this._actions = options.actions || {};
    // 2.做响应式状态state属性
    // Vue.util.defineReactive(this, 'state', {})
    this._vm = new Vue({
      data: {
        $$state: options.state,
      },
    });
    // 上下文绑定
    this.commit = this.commit.bind(this)
    this.dispatch = this.dispatch.bind(this)
    // getters
    // 1.动态设置getters属性
    // 2.响应式
    // 附加:能否利用上vue computed
    this.getters = {}
  }
  // 给用户暴露接口
  get state() {
    // console.log(this._vm);
    return this._vm._data.$$state;
  }
  set state(v) {
    console.error("please use replaeState to reset state");
  }
  // store.commit(type, payload)
  commit(type, payload) {
    // 获取mutations
    const entry = this._mutations[type];
    console.log(entry,'entry')
    if (!entry) {
      console.error("unknown mutation type");
    }
    entry(this.state, payload);
  }
  dispatch(type, payload) {
    // 获取actions
    const entry = this._actions[type];
    if (!entry) {
      console.error("unknown actions type");
    }
    // {commit, dispatch, state, getters}
    entry(this, payload);
  }
}
function install(_Vue) {
  Vue = _Vue;
  // 挂载$store
  Vue.mixin({
    beforeCreate() {
      if (this.$options.store) {
        // 给每个组件实例暴露store实例
        Vue.prototype.$store = this.$options.store;
      }
    },
  });
}
// 导出对象相当于Vuex
export default { Store, install };

2、在当前kstore文件夹中的index.js里引入kvuex.js文件

import Vue from 'vue'
import Vuex from './kvuex'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    add(state) {
      // state从哪来
      state.count++
    }
  },
  actions: {
    // 上下文对象是什么,从哪来
    add({commit}) {
      setTimeout(() => {
        commit('add')
      }, 1000);
    }
  },
  getters: {
    doubleCounter: state => {
      return state.count * 2;
    }
  },
  modules: {
  }
})