store.ts 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. import { reactive, isRef, isReactive, toRaw, ComputedRef, toRef, effectScope, unref } from 'vue'
  2. import { v4 } from 'uuid'
  3. import { Store, StoreState, StoreToRefs } from './types'
  4. /**
  5. * 判断是否 ComputedRef 类型
  6. * @param obj
  7. * @returns
  8. */
  9. function isComputed(obj: unknown): obj is ComputedRef {
  10. return !!(isRef(obj) && Reflect.has(obj, 'effect'))
  11. }
  12. /**
  13. * 定义一个 store 对象
  14. * @param createStore
  15. * @param id
  16. * @returns
  17. */
  18. export function defineStore<T extends object>(createStore: () => T, id = v4()) {
  19. const scope = effectScope()
  20. const store = scope.run(() => createStore()) as T
  21. // 将 store 中的响应式属性转化为 ref 属性
  22. const $toRefs = () => {
  23. const result = Object.create(null)
  24. for (const key in store) {
  25. const value = store[key]
  26. if (isRef(value)) {
  27. result[key] = value
  28. } else if (isReactive(value)) {
  29. result[key] = toRef(store, key)
  30. }
  31. }
  32. return result as StoreToRefs<T>
  33. }
  34. // 更新 state 状态
  35. const $setState = (callback: (state: StoreState<T>) => void) => {
  36. const state = Object.create(null)
  37. for (const key in store) {
  38. const value = store[key]
  39. if (!isComputed(value) && (isRef(value) || isReactive(value))) {
  40. state[key] = value
  41. }
  42. }
  43. callback(reactive(state))
  44. }
  45. // 将 state 重设为初始状态
  46. const $reset = () => {
  47. const newScope = effectScope()
  48. const newStore = scope.run(() => createStore()) as T
  49. for (const key in store) {
  50. const item = store[key]
  51. if (!isComputed(item) && isRef(item)) {
  52. item.value = unref(newStore[key])
  53. }
  54. if (isReactive(item)) {
  55. for (const prop in item) {
  56. item[prop] = newStore[key][prop]
  57. }
  58. }
  59. }
  60. newScope.stop()
  61. }
  62. // 销毁当前的 store
  63. const $dispose = () => {
  64. scope.stop()
  65. }
  66. const $store: Store<T> = reactive({
  67. $id: id,
  68. $toRefs,
  69. $setState,
  70. $reset,
  71. $dispose,
  72. ...store
  73. })
  74. return () => $store
  75. }
  76. /**
  77. * 将 store 中的响应式属性转化为 ref 属性
  78. * @param store
  79. * @returns
  80. */
  81. export function storeToRefs<T extends object>(store: Store<T>) {
  82. const raw = toRaw(store)
  83. const result = Object.create(null)
  84. for (const key in raw) {
  85. const value = raw[key]
  86. if (isRef(value)) {
  87. result[key] = value
  88. } else if (isReactive(value)) {
  89. result[key] = toRef(raw, key)
  90. }
  91. }
  92. return result as StoreToRefs<T>
  93. }