模拟Vuex插件

需求

Vuex是一个帮助我们集中管理vue组件状态的状态管理插件,我们将模拟它的state、mutation、action、getter。在组件内,我们可以通过vm. s t o r e . c o m m i t ( ) 来 更 改 s t a t e , 或 者 使 用 v m . store.commit()来更改state,或者使用vm. store.commit()state使vm.store.dispatch()来异步地改变state,同时阻止用户通过vm. s t o r e . s t a t e = ′ ′ 这 种 方 式 直 接 改 变 s t a t e ; 用 户 可 以 使 用 store.state=''这种方式直接改变state;用户可以使用 store.state=state使store.getters()来获取state,当state改变时,获取的值也做相应的改变。

实现

首先,我们创建一个简单的Store

  • index.js
import Vue from 'vue'
import Vuex from './kstorevuex.js'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    count: 1
  },
  mutations: {
    SET_COUNT(state, value) {
      state.count = value
    }
  },
  actions: {
    ASYNC_COUNT(state, value) {
      setTimeout(() => {
        state.count = value
      }, 2000)
    }
  },
  getters: {
    GET_COUNT(state) {
      return state.count
    }
  }
})

和vue-router一样,我们要实现一个Store类和install方法,但是注意我们使用的时候是new Vuex.Store,所以,KVuex文件应该是这样的

  • KVuex.js
let Vue

class Store {
  constructor(options) {}
}
function install(_vue) {}
export default { Store, install }

同样的,我们要在install方法中将$store挂到Vue原型链上,方便组件来调用。

  • function install
function install(_vue) {
  // 这里和仿vue-router组件是一样的
  Vue = _vue
  Vue.mixin({
    beforeCreate() {
      if (this.$options.store) {
        Vue.prototype.$store = this.$options.store
      }
    }
  })
}

在class Store中,我们要实现getter、commit、dispatch这三个方法;和仿vue-router不同的是,我们创建响应式数据的方式有所变化,值得注意的一点是利用computed选项实现getter。

  • class Store
class Store {
  constructor(options) {
    // 将action和mutation存入this
    this._mutations = options.mutations
    this._actions = options.actions
    this._wrapGetters = options.getters
    this.getters = {}
    // 利用computed选项实现getter,避免this指向混乱,使用一个变量保存this
    const store = this
    let computed = {}
    // 遍历vuex的getter配置项
    Object.keys(store._wrapGetters).forEach(key => {
      const f = store._wrapGetters[key]
      // 由于computed里面的函数没有参数,所以这里稍微处理一下
      computed[key] = () => {
        return f(store.state)
      }
      // 设置store.getter只读
      Object.defineProperty(store.getters, key, {
        get: () => {
          return store._vm[key]
        }
      })
    })
    // 创建一个响应式的$$state属性,不使用defineReactive()方法是因为实现getter方法需要使用computed选项,state前面加两个$可以不让vue自动代理$$state
    this._vm = new Vue({
      data: {
        $$state: options.state
      },
      computed
    })

    // 将commit和dispatch从this中解构出来
    const { commit, dispatch } = store
    this.commit = function(type, payload) {
      commit.call(store, type, payload)
    }
    this.dispatch = function(type, payload) {
      dispatch.call(store, type, payload)
    }
  }

  // 使用getter,返回state
  get state() {
    return this._vm._data.$$state
  }
  // 阻止用户直接修改state
  set state(val) {
    console.error('you can not change state by direct assignment "' + val + '"')
  }

  // 创建一个commit方法和dispatch方法
  commit(type, payload) {
    const entry = this._mutations[type]
    if (!entry) {
      console.error('unknown mutation type:' + type)
    }
    entry(this.state, payload)
  }
  dispatch(type, payload) {
    const entry = this._actions[type]
    if (!entry) {
      console.error('unknown action type:' + type)
    }
    entry(this.state, payload)
  }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值