@idooel/runtime-context
Version:
Runtime data pool with namespaces, stackable contexts, subscriptions and optional persistence. Vue adapter included.
118 lines (102 loc) • 3.19 kB
text/typescript
import Vue from 'vue'
import { createDataPool, DataPool } from '../core/DataPool'
import type { Namespace, DataKey, Subscriber, DataEvent } from '../core/types'
declare module 'vue/types/vue' {
interface Vue {
$idooelDataPool: DataPool
}
}
export interface Vue2DataPoolOptions {
pool?: DataPool
globalInject?: boolean
mixin?: boolean
}
const Vue2DataPoolPlugin = {
install(Vue: any, options: Vue2DataPoolOptions = {}) {
const pool = options.pool || createDataPool()
// 全局注入
if (options.globalInject !== false) {
Vue.prototype.$idooelDataPool = pool
Vue.$idooelDataPool = pool
}
// 全局混入
if (options.mixin !== false) {
Vue.mixin({
created() {
// 为每个组件创建数据池引用
this._idooelDataPoolSubscriptions = []
},
beforeDestroy() {
// 清理订阅
if (this._idooelDataPoolSubscriptions) {
this._idooelDataPoolSubscriptions.forEach((unsub: any) => {
try {
unsub()
} catch {
// 忽略取消订阅时的错误
}
})
this._idooelDataPoolSubscriptions = []
}
}
})
}
}
}
export function useDataPool(): DataPool {
if (!Vue.prototype.$idooelDataPool) {
throw new Error('Vue2DataPool plugin not installed. Please install it with Vue.use(Vue2DataPoolPlugin)')
}
return Vue.prototype.$idooelDataPool
}
export function usePoolValue<T = unknown>(
ns: Namespace,
key: DataKey,
fallback?: T
) {
const pool = useDataPool()
// 创建响应式数据
const value = Vue.observable({
data: pool.get(ns, key, fallback)
})
// 获取当前组件实例
const vm = Vue.prototype._isVue ? Vue.prototype : getCurrentVueInstance()
if (vm && vm._idooelDataPoolSubscriptions) {
// 订阅数据变更
const unsubscribe = pool.subscribe<T>({ ns, key }, (event: DataEvent<T>) => {
value.data = event.value
})
vm._idooelDataPoolSubscriptions.push(unsubscribe)
}
return {
value: value.data,
set: (newValue: T) => pool.set(ns, key, newValue),
delete: () => pool.delete(ns, key)
}
}
export function usePoolSubscription<T = unknown>(
filter: { ns?: Namespace; key?: DataKey },
callback: Subscriber<T>
) {
const pool = useDataPool()
const vm = getCurrentVueInstance()
if (vm && vm._idooelDataPoolSubscriptions) {
const unsubscribe = pool.subscribe<T>(filter, callback)
vm._idooelDataPoolSubscriptions.push(unsubscribe)
return unsubscribe
}
return pool.subscribe<T>(filter, callback)
}
// 辅助函数:获取当前 Vue 实例
function getCurrentVueInstance(): any {
// 在 Vue 2 中,通过全局混入的 created 钩子可以访问当前实例
// 这里需要通过其他方式获取实例,实际使用中可以通过函数调用上下文获取
try {
// 尝试获取当前组件实例(这需要在特定上下文中调用)
return Vue.prototype._isVue ? Vue.prototype : null
} catch {
return null
}
}
export { Vue2DataPoolPlugin, createDataPool }
export default Vue2DataPoolPlugin