实现简单vuex

224 阅读1分钟

vuex的使用

store/index.js

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

Vue.use(KVuex);

export default new KVuex.Store({
  state: {
    count: 0
  },
  mutations: {
    add(state, num) {
      state.count += num
    }
  },
  getters: {
    score: (state) => state.count + 2
  },
  actions: {
    asyncAdd({ commit }) {
      commit('add', 3)
    }
  }
})

main.js

import Vue from "vue";
import App from "./App.vue";
import store from './store'

Vue.config.productionTip = false;

Vue.prototype.$bus = new Vue();

new Vue({
  store,
  render: h => h(App)
}).$mount("#app");

组件内使用

<template>
  <div>
    <h3>vuex test</h3>
    <p>{{$store.state.count}}</p>
    <p>{{$store.getters.score}}</p>
    <button @click="add">add</button>
    <button @click="asyncAdd">asyncAdd</button>
  </div>
</template>

<script>
export default {
  name: 'VueStudyKvuextest',

  data() {
    return {

    };
  },

  mounted() {

  },

  methods: {
    add() {
      this.$store.commit('add', 1)
    },
    asyncAdd() {
      this.$store.dispatch('asyncAdd')
    }
  },
};
</script>

<style lang="scss" scoped>
</style>

vuex实现

定义Store类

vuex的实例$store会提供两个方法:commit和dispatch,所以在Store类内需要实现这两个方法,commi本质上是去调用mutation里面对应的方法,dispatch本质也是通过对应的actions再去调用mutation里面的方法,需要注意的是由于getters里面的属性都是只读的,所以需要单独处理为只读属性

class Store {
  constructor(options = {}) {
    //定义state,利用vue设置为响应式
    this.state = new Vue({
      data: options.state
    })
    //初始化mutation,用于commit调用
    this.mutations = options.mutations || {}
    //初始化actions
    this.actions = options.actions || {}
    options.getters && this.handleGetter(options.getters)
  }
  commit = (type, arg) => {
    const fn = this.mutations[type]
    fn(this.state, arg)
  }
  dispatch = (type, arg) => {
    const fn = this.actions[type]
    fn({ commit: this.commit, state: this.state }, arg)
  }
  handleGetter(getters) {
    this.getters = {}
    Object.keys(getters).forEach(key => {
      Object.defineProperty(this.getters, key, {
        get: () => getters[key](this.state)
      })
    })
  }
}
export default { Store }

定义install方法

利用install方法里传入的vue对象,执行混入,判断如果是根组件的话就在beforeCreate生命周期里就在vue的prototype上挂载 $store

let Vue
function install(_vue) {
  // 接受vue.use()时传进来的vue对象
  Vue = _vue
  //执行混入
  Vue.mixin({
    beforeCreate() {
      // 判断当前组件选项中是否有store,有的话则为根组件
      if (this.$options.store) {
        //在Vue的protopyte上挂在$store,值为根组件上传入的store(本质是Vuex的实例对象)
        Vue.prototype.$store = this.$options.store
      }
    },
  });
}

完整代码

//定义install方法,执行混入,在vue原型上挂在$store

//创建 Store 类 ,
let Vue
function install(_vue) {
  // 接受vue.use()时传进来的vue对象
  Vue = _vue
  //执行混入
  Vue.mixin({
    beforeCreate() {
      // 判断当前组件选项中是否有store,有的话则为根组件
      if (this.$options.store) {
        //在Vue的protopyte上挂在$store,值为根组件上传入的store(本质是Vuex的实例对象)
        Vue.prototype.$store = this.$options.store
      }
    },
  });
}

class Store {
  constructor(options = {}) {
    //定义state,利用vue设置为响应式
    this.state = new Vue({
      data: options.state
    })
    //初始化mutation,用于commit调用
    this.mutations = options.mutations || {}
    //初始化actions
    this.actions = options.actions || {}
    options.getters && this.handleGetter(options.getters)
  }
  commit = (type, arg) => {
    const fn = this.mutations[type]
    fn(this.state, arg)
  }
  dispatch = (type, arg) => {
    const fn = this.actions[type]
    fn({ commit: this.commit, state: this.state }, arg)
  }
  handleGetter(getters) {
    this.getters = {}
    Object.keys(getters).forEach(key => {
      Object.defineProperty(this.getters, key, {
        get: () => getters[key](this.state)
      })
    })
  }
}
export default { Store, install }