保存
This commit is contained in:
87
src/common/hooks/useObservableVue.ts
Normal file
87
src/common/hooks/useObservableVue.ts
Normal file
@@ -0,0 +1,87 @@
|
||||
import { reactive, onBeforeUnmount, type Reactive } from 'vue'
|
||||
import type { IObservable } from '@/core/state/IObservable.ts'
|
||||
|
||||
/**
|
||||
* Vue Hook: useObservable
|
||||
* 支持深层解构赋值,直接修改触发 ObservableImpl 通知 + Vue 响应式更新
|
||||
* @example
|
||||
* interface AppState {
|
||||
* count: number
|
||||
* user: { name: string; age: number }
|
||||
* items: number[]
|
||||
* }
|
||||
*
|
||||
* // 创建 ObservableImpl
|
||||
* const obs = new ObservableImpl<AppState>({
|
||||
* count: 0,
|
||||
* user: { name: 'Alice', age: 20 },
|
||||
* items: []
|
||||
* })
|
||||
*
|
||||
* export default defineComponent({
|
||||
* setup() {
|
||||
* // 深层解构 Hook
|
||||
* const { count, user, items } = useObservable(obs)
|
||||
*
|
||||
* const increment = () => {
|
||||
* count += 1 // 触发 ObservableImpl 通知 + Vue 更新
|
||||
* }
|
||||
*
|
||||
* const changeAge = () => {
|
||||
* user.age = 30 // 深层对象也能触发通知
|
||||
* }
|
||||
*
|
||||
* const addItem = () => {
|
||||
* items.push(42) // 数组方法拦截,触发通知
|
||||
* }
|
||||
*
|
||||
* return { count, user, items, increment, changeAge, addItem }
|
||||
* }
|
||||
* })
|
||||
*/
|
||||
export function useObservable<T extends object>(observable: IObservable<T>): Reactive<T> {
|
||||
// 创建 Vue 响应式对象
|
||||
const state = reactive({} as T)
|
||||
|
||||
/**
|
||||
* 将 ObservableImpl Proxy 映射到 Vue 响应式对象
|
||||
* 递归支持深层对象
|
||||
*/
|
||||
function mapKeys(obj: any, proxy: any) {
|
||||
(Object.keys(proxy) as (keyof typeof proxy)[]).forEach(key => {
|
||||
const value = proxy[key]
|
||||
if (typeof value === 'object' && value !== null) {
|
||||
// 递归创建子对象 Proxy
|
||||
obj[key] = reactive({} as typeof value)
|
||||
mapKeys(obj[key], value)
|
||||
} else {
|
||||
// 基本类型通过 getter/setter 同步
|
||||
Object.defineProperty(obj, key, {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
get() {
|
||||
return proxy[key]
|
||||
},
|
||||
set(val) {
|
||||
proxy[key] = val
|
||||
},
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 获取 ObservableImpl 的 Proxy
|
||||
const refsProxy = observable.toRefsProxy()
|
||||
mapKeys(state, refsProxy)
|
||||
|
||||
// 订阅 ObservableImpl,保持响应式同步
|
||||
const unsubscribe = observable.subscribe(() => {
|
||||
// 空实现即可,getter/setter 已同步
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
unsubscribe()
|
||||
})
|
||||
|
||||
return state
|
||||
}
|
||||
Reference in New Issue
Block a user