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

如何从Excel自定义函数接入Angular应用?

Excel加载项:Angular任务窗格与外部自定义函数/功能区命令的复用方案

核心思路:通过全局对象复用Angular服务

Angular启动后,将应用的依赖注入能力暴露到全局,让外部的自定义函数、功能区命令能直接获取已配置好的服务实例,无需重新初始化,完全复用拦截器、认证头等配置。

具体实现方案

方案1:暴露Angular注入器到全局

这是最直接的复用方式,利用Angular的注入器获取已初始化的服务:

  1. Angular启动时挂载注入器
    在main.ts中完成Office初始化后,把应用的注入器存到window对象:
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { Injector } from '@angular/core';

Office.onReady().then(() => {
  platformBrowserDynamic().bootstrapModule(AppModule)
    .then(moduleRef => {
      // 用唯一命名避免全局冲突
      (window as any).excelAddinInjector = moduleRef.injector;
    })
    .catch(err => console.error(err));
});
  1. 外部代码调用Angular服务
    在自定义函数或功能区命令的代码里,通过全局注入器获取服务实例:
// 自定义函数示例
async function getCustomData(input: string): Promise<string> {
  const injector = (window as any).excelAddinInjector;
  if (!injector) return '错误:Angular应用未启动';
  
  // 获取已配置好的ThingService
  const thingService = injector.get(ThingService);
  try {
    const result = await thingService.fetchData(input);
    return result.toString();
  } catch (err) {
    return `请求失败:${(err as Error).message}`;
  }
}

// 功能区命令示例
function ribbonAction() {
  const injector = (window as any).excelAddinInjector;
  if (!injector) return;
  
  const thingService = injector.get(ThingService);
  thingService.performAction().then(() => {
    Office.context.ui.notifySuccess('操作完成');
  });
}

方案2:全局事件监听通信

你提到的window事件监听方案完全可行,适合需要解耦的场景:

  1. Angular端监听全局事件
    在根组件中监听自定义事件,处理后返回结果:
import { HostListener } from '@angular/core';
import { ThingService } from './services/thing.service';

export class AppComponent {
  constructor(private thingService: ThingService) {}

  @HostListener('window:callAngularService', ['$event'])
  handleServiceCall(event: CustomEvent) {
    const { input, callbackId } = event.detail;
    this.thingService.fetchData(input)
      .then(result => {
        // 触发结果事件返回数据
        window.dispatchEvent(new CustomEvent('angularServiceResult', {
          detail: { callbackId, result }
        }));
      })
      .catch(err => {
        window.dispatchEvent(new CustomEvent('angularServiceResult', {
          detail: { callbackId, error: err.message }
        }));
      });
  }
}
  1. 外部代码触发事件并接收结果
    在自定义函数中触发事件,监听结果返回:
function getCustomData(input: string): Promise<string> {
  return new Promise((resolve) => {
    const callbackId = Math.random().toString(36).slice(2);
    // 监听结果事件
    const resultHandler = (event: CustomEvent) => {
      if (event.detail.callbackId === callbackId) {
        window.removeEventListener('angularServiceResult', resultHandler);
        if (event.detail.error) {
          resolve(`错误:${event.detail.error}`);
        } else {
          resolve(event.detail.result.toString());
        }
      }
    };
    window.addEventListener('angularServiceResult', resultHandler);
    
    // 触发调用事件
    window.dispatchEvent(new CustomEvent('callAngularService', {
      detail: { input, callbackId }
    }));
  });
}

注意事项

  • 确保Angular应用完全启动后再执行外部代码,可通过判断全局注入器是否存在或设置启动完成标志位实现。
  • 全局对象和事件名称用独特命名(比如带上你的加载项前缀),避免和其他脚本冲突。
  • 自定义函数运行在独立上下文时,需确认window对象是否与任务窗格共享(部分Excel环境中自定义函数有独立运行环境,此时需用Office的跨上下文通信API补充)。

内容的提问来源于stack exchange,提问作者celluj34

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 11:15:14