Vue3 丐版 Vuex

Vue3 丐版 Vuex

// src/common/myVuex.ts
import { App, inject, Plugin, reactive } from 'vue'

// 基本功能类型
type StoreType<T = any> = {
  state: T,
  mutations?: { [key: string]: (state: T, payload?: unknown) => void },
  actions?: { [key: string]: (context: StoreType<T>, payload?: unknown) => void },
  getters?: { [key: string]: (state: T) => unknown }
}
// storeKey
const storeKey = 'store'
// Store 类
class Store<T = any> {
  // 载入方法
  install: Plugin['install']
  // 私有属性
  private $state: T
  private _mutations: { [key: string]: (state: T, payload?: unknown) => void }
  private _actions: { [key: string]: (context: StoreType<T>, payload?: unknown) => void }
  private _getters: { [key: string]: (state: T) => unknown }
  // 初始化
  constructor (store: StoreType<T>) {
    // 使用 reactive 创建 state,使其变成响应式对象
    this.$state = reactive<any>(store.state)
    this._mutations = store.mutations || {}
    this._actions = store.actions || {}
    this._getters = store.getters || {}
  }
  
  // commit
  commit = (type: string, payload?: unknown) => {
    const fn = this._mutations[type]
    if (fn) {
      fn(this.$state, payload)
    }
  }
  
  // dispatch
  dispatch = async (type: string, payload?: unknown) => {
    const fn = this._actions[type]
    if (fn) {
      await fn(this, payload)
    }
  }
  
  // 暴露 state
  get state (): T {
    return this.$state
  }

  // 暴露 getters
  get getters () {
    const result = {} as any
    Object.keys(this._getters).forEach(key => {
      result[key] = this._getters[key](this.$state)
    })
    return result
  }
}
// 创建 store
function createStore<T = any> (options: StoreType<T>): Plugin {
  return new Store(options) as Plugin
}

// 注册插件
Store.prototype.install = function (app: App, injectKey) {
  // 将 $store 注入到全局
  app.config.globalProperties.$store = this
  // 使用 provide 提供 stote
  app.provide(injectKey || storeKey, this)
}

// store Hook
function useStore<T = any> (key?: string | null): Store<T> {
  if (!key) key = null
  // inject 注入 store
  const store = inject<Store<T>>(key !== null ? key : storeKey) as Store<T>
  return store
}

export default { createStore, useStore }

使用

// src/main.ts
import { createApp } from 'vue'
import App from './App.vue'
import Store from './common/myVuex'

const store = Store.createStore({
  state: {
    count: 0
  },
  mutations: {
    add: (state: { count: number }) => {
      state.count++
    }
  },
  actions: {
    'sync-add': async (context: any) => {
      await new Promise<void>((resolve, reject) => {
        const timer = setTimeout(() => {
          clearTimeout(timer)
          context.commit('add')
          resolve()
        }, 1000)
      })
    }
  },
  getters: {
    count2: (state) => {
      return state.count * 2
    }
  }
})

// 注入
createApp(App).use(store).mount('#app')
<!-- src/components/HelloWorld.vue -->
<template>
  <div class="hello">
    <p>{{ count }}</p>
    <button @click="clickHandle">add</button>
  </div>
</template>

<script lang="ts">
import { computed, defineComponent } from 'vue'
import Store from '@/common/myVuex'
export default defineComponent({
  props: {
    msg: String
  },
  setup () {
    const store = Store.useStore<{ count: number }>('aaa')
    const count = computed(() => store.getters.count2)
    const clickHandle = async () => {
      await store.dispatch('sync-add')
      console.log(store.state)
    }
    return {
      count,
      clickHandle
    }
  }
})
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {
  margin: 40px 0 0;
}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  display: inline-block;
  margin: 0 10px;
}
a {
  color: #42b983;
}
</style>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值