You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在触发事件中更新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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 03:15:19