实现一个简单的vuex

2020-04-27  本文已影响0人  杨晨1994

首先我们先看下vuex的使用方式一般都是下面这样的

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
  state: {
    count:0
  },
  mutations: {
    changeCount (state,num) {
      state.count += num
    }
  },
  actions: {
    changeCount (context,num) {
      setTimeout(()=>{
        context.commit('changeCount',num)
      },2000)
    }
  },
  getters: {
    doubleCount (state){
      return state.count*2
    }
  }
})

有个组件是这样的

<template>
  <div>
    <div>数量--{{$store.state.count}}</div>
    <div>双倍数量--{{$store.getters.doubleCount}}</div>
    <button @click="handleClick">点击加1</button>
    <button @click="deferHandleClick">点击延迟加2</button>
  </div>
</template>

<script>
export default {
  name: 'Home',
  methods:{
    handleClick () {
      this.$store.commit('changeCount',1)
    },
    deferHandleClick () {
      this.$store.dispatch('changeCount',2)
    }
  }
}
</script>

我们要实现一个vuex主要有几个要点

  • vuex是一个插件,通过Vue.use使用
  • vuex里面有一个store类
  • 实现state,mutations,actions,getters
  • state改变的时候 通知组件数据变更

首先vuex是这样使用的


image.png

vuex里面有一个Store类,然后知道vuex是一个插件,通过Vue.use使用。
那么我们新建一个kVuex.js,代码里面应该有个Store类和一个install方法,大概是这样的

class Store {
}
function install(_vue) { // install方法接受一个vue的形参
}
export default {Store,install}

我们的main.js是这样的 把引入的store挂载到了vue根组件上

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
Vue.config.productionTip = false
new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app')

所以我们的install方法是这样的

let Vue; 
class Store {
}
function install(_vue) {// 接受一个参数 是vue
 Vue = _vue // 这里我们保存一下vue 一会还要用
  Vue.mixin({ // Vue构造器注入beforeCreate方法
    beforeCreate() {
      if(this.$options.store){ // 因为在上面代码中store只挂载到了根组件 所以下面的代码只在根组件执行
        Vue.prototype.$store = this.$options.store
      }
    }
  })
}
export default {Store,install}

现在我们开始实现state,要知道我们的state是响应式的,state发生变化的时候,组件会发生变化

let Vue;
class Store {
  constructor (options){
    this.state = new Vue({ // 利用vue的数据响应式原理 这也是为什么vuex只能在vue里用的原因
      data:{
        state:options.state
      }
    })
  }
}
function install(_vue) {
  Vue = _vue
  Vue.mixin({
    beforeCreate() {
      if(this.$options.store){
        Vue.prototype.$store = this.$options.store
      }
    }
  })
}
export default {Store,install}

实现mutations我们只需要加个映射就可以,但是我们是通过commit调用的,所以我们要实现commit方法

let Vue;
class Store {
  constructor (options){
    this.state = new Vue({ // 利用vue的数据响应式原理
      data:options.state
    })
    this.mutations = options.mutations;//传进来的mutations
  }
  commit = (type,arg)=>{ // commit方法接受一个类型和参数 类型就是你调用的时候传的方法名
    // 在组件里我们是这样用的this.$store.commit('changeCount',1)
    this.mutations[type](this.state,arg) // 执行mutations里面的方法
  }
}
function install(_vue) {
  Vue = _vue
  Vue.mixin({
    beforeCreate() {
      if(this.$options.store){
        Vue.prototype.$store = this.$options.store
      }
    }
  })
}
export default {Store,install}

实现actions一样也是加个映射关系。但是我们还要实现dispatch方法

let Vue;
class Store {
  constructor (options){
    this.state = new Vue({ // 利用vue的数据响应式原理
      data:options.state
    })
    this.mutations = options.mutations;//传进来的mutations
    this.actions = options.actions;//传进来的actions
  }
  commit = (type,arg)=>{ // commit方法接受一个类型和参数 类型就是你调用的时候传的方法名
    // 在组件里我们是这样用的this.$store.commit('changeCount',1)
    this.mutations[type](this.state,arg) // 执行mutations里面的方法
  }
  dispatch (type,arg) {// dispatch方法接受一个类型和参数 类型就是你调用的时候传的方法名
    this.actions[type]({
      commit:this.commit
    },arg)
  }
}
function install(_vue) {// 接受一个参数 是vue
  Vue = _vue // 这里我们保存一下vue 一会还要用
  Vue.mixin({ // Vue构造器注入beforeCreate方法
    beforeCreate() {
      if(this.$options.store){ // 因为在上面代码中store只挂载到了根组件 所以下面的代码只在根组件执行
        Vue.prototype.$store = this.$options.store
      }
    }
  })
}
export default {Store,install}

实现getters 就不能简单的加个映射了

let Vue;
class Store {
  constructor (options){
    this.state = new Vue({ // 利用vue的数据响应式原理
      data:options.state
    })
    this.mutations = options.mutations;//传进来的mutations
    this.actions = options.actions;//传进来的actions
    this.getters = {}; //添加getters为{}
    options.getters && this.handleGetter(options.getters) // 当传入的getters存在的话 执行handleGetter
  }
  commit = (type,arg)=>{ // commit方法接受一个类型和参数 类型就是你调用的时候传的方法名
    // 在组件里我们是这样用的this.$store.commit('changeCount',1)
    this.mutations[type](this.state,arg) // 执行mutations里面的方法
  }
  dispatch (type,arg) {// dispatch方法接受一个类型和参数 类型就是你调用的时候传的方法名
    // 在组件里我们是这样用的this.$store.dispatch('changeCount',2)
    this.actions[type]({  // 执行actions里面的方法
      commit:this.commit
    },arg)
  }
  handleGetter (getters){
    Object.keys(getters).forEach(key=>{ // 拿出getters的key做一个循环
      Object.defineProperty(this.getters,key,{ // 给this.getter添加属性,属性名为key这个变量,并添加get方法
        get: ()=> {
          return getters[key](this.state) // 执行getters里面的方法传参   并return出去
        }
      })
    })
  }
}
function install(_vue) {// 接受一个参数 是vue
  Vue = _vue // 这里我们保存一下vue 一会还要用
  Vue.mixin({ // Vue构造器注入beforeCreate方法
    beforeCreate() {
      if(this.$options.store){ // 因为在上面代码中store只挂载到了根组件 所以下面的代码只在根组件执行
        Vue.prototype.$store = this.$options.store
      }
    }
  })
}
export default {Store,install}

到此我们这个简单的vuex就完成了

上一篇 下一篇

猜你喜欢

热点阅读