Vue 3.x 简单实现一个自己的 vue Store

发布于 2025-02-21 22:56:09 字数 2694 浏览 7 评论 0

plugins/store/index.js

let Vue

class Store {
  constructor (options = {}) {
    // this.vm = new Vue({
    //   data: {
    //     $state: options.state,  // 以$开头的属性不会被 vm 直接访问到(vm.$state === undefined)
    //   },
    // })
    this._state = options.state || {}
    this._getters = options.getters || {}
    this._mutations = options.mutations || {}
    this._actions = options.actions || {}
    this.getters = {}
    const store = this
    Object.keys(this._getters).forEach(key => {
      Object.defineProperty(this.getters, key, {
        get () {
          return store._getters[key](store.state, store.getters)
        },
        enumerable: true,
      })
    })
    // 绑定 commit 上下⽂否则 action 中调⽤commit 时可能出问题!!
    // 同时也把 action 绑了,因为 action 可以互调
    const { commit, dispatch } = store
    this.commit = function (...arg) {
      commit.apply(store, arg)
    }
    this.dispatch = function (...arg) {
      dispatch.apply(store, arg)
    }
  }

  get state () {
    // return this.vm._data.$state  // (vm._data 等同于 vm.$data)
    return Vue.observable(this._state)
  }

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

  commit (type, payload) {
    const mutationType = this._mutations[type]
    if (!mutationType) {
      console.error(`unknown mutation type ${type}`)
      return
    }
    mutationType(this.state, payload)
  }

  dispatch (type, payload) {
    const actionType = this._actions[type]
    if (!actionType) {
      console.error(`unknown action type ${type}`)
    }
    actionType({
      state: this.state,
      commit: this.commit,
    }, payload)
  }
}

function install (_Vue) {
  Vue = _Vue
  Vue.mixin({
    beforeCreate () {
      if (this.$options.store) {
        Vue.prototype.$store = this.$options.store
      }
    },
  })
}

export default {
  Store,
  install,
}

store/index.js

import Vue from 'vue'
import Vuex from '@/plugins/store/index.js'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    count: 1,
  },
  getters: {
    doubleCounter (state) {
      return state.count * 2
    },
  },
  mutations: {
    addCount (state, payload) {
      state.count += payload
    },
  },
  actions: {
    addCountAsync ({ state, commit }, payload) {
      setTimeout(() => {
        commit('addCount', state.count + payload)
      }, 3000)
    },
  },
})

main.js

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

Vue.config.productionTip = false

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

文章
评论
26 人气
更多

推荐作者

闻呓

文章 0 评论 0

深府石板幽径

文章 0 评论 0

mabiao

文章 0 评论 0

枕花眠

文章 0 评论 0

qq_CrTt6n

文章 0 评论 0

红颜悴

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文