如何在触发事件中更新Rune全局状态?解决生命周期报错问题
解决方案
问题根源
getContext 依赖Qwik组件的生命周期上下文,而Word内容控件的onDataChanged回调属于插件全局事件,不在组件上下文范围内,直接调用getDocState()会触发生命周期错误。以下是几种可行的解决方式:
方案1:提前传递DocState实例给Service
在组件初始化时,把组件上下文里的DocState实例传递给service,让service持有引用,后续事件触发时直接用这个实例更新状态。
修改service.ts
// 存储DocState实例的全局变量 let docStateInstance: DocState | null = null; // 对外暴露设置实例的方法 export function setDocStateForService(instance: DocState) { docStateInstance = instance; } // 修改事件回调逻辑 async function contentControlDataChanged(event: Word.ContentControlDataChangedEventArgs) { if (!docStateInstance) return; const control = event.contentControl; if (control.title) { docStateInstance.add(control.title, control.text); } }
在组件中传递实例
import { getDocState } from './doc-state'; import { setDocStateForService } from './service'; // 组件初始化时完成实例传递 useVisibleTask$(() => { const docState = getDocState(); setDocStateForService(docState); });
方案2:将DocState改为全局单例
放弃使用setContext/getContext,直接把DocState做成单例,让service和组件都能直接访问这个全局实例,彻底避开上下文依赖问题。
修改doc-state.ts
export class DocState { #properties = $state(new Map()); constructor() {} add(prop: string, value: string) { this.#properties.set(prop, value); } set(props: Word.DocumentProperties, controls: Word.ContentControl[]) { const _P = props as any; for (const p of coreProperties) { if (_P[p]) { this.#properties.set(p, _P[p]); } } for (const c of controls) { if (c.title) { this.#properties.set(c.title, c.text); } } return this.#properties; } get(prop: string) { return this.#properties.get(prop); } getAll() { return this.#properties; } } // 直接导出单例实例 export const docState = new DocState(); // 移除原有的setDocState和getDocState方法
组件中使用单例
import { docState } from './doc-state'; const { properties } = docState.getAll();
service.ts中使用单例
import { docState } from './doc-state'; async function contentControlDataChanged(event: Word.ContentControlDataChangedEventArgs) { const control = event.contentControl; if (control.title) { docState.add(control.title, control.text); } }
方案3:用事件总线实现跨上下文通信
service在事件触发时发布更新消息,组件在自身上下文里订阅消息并更新状态,让service无需直接访问组件上下文的状态。
创建事件总线(event-bus.ts)
type EventHandler = (data: { prop: string; value: string }) => void; class EventBus { private handlers: Map<string, EventHandler[]> = new Map(); on(event: string, handler: EventHandler) { if (!this.handlers.has(event)) { this.handlers.set(event, []); } this.handlers.get(event)!.push(handler); } emit(event: string, data: { prop: string; value: string }) { this.handlers.get(event)?.forEach(handler => handler(data)); } } export const eventBus = new EventBus();
修改service.ts
import { eventBus } from './event-bus'; async function contentControlDataChanged(event: Word.ContentControlDataChangedEventArgs) { const control = event.contentControl; if (control.title) { // 发布内容控件更新事件 eventBus.emit('content-control-updated', { prop: control.title, value: control.text }); } }
在组件中订阅事件
import { getDocState } from './doc-state'; import { eventBus } from './event-bus'; useVisibleTask$(() => { const docState = getDocState(); const updateHandler = (data: { prop: string; value: string }) => { docState.add(data.prop, data.value); }; eventBus.on('content-control-updated', updateHandler); // 组件销毁时清理订阅 return () => { // 可扩展事件总线的off方法实现订阅移除 }; });
内容的提问来源于stack exchange,提问作者kjoetools
相关产品推荐
相关产品推荐

