本文介绍了如何使用 Angular 2+ 将 Office 加载项创建为单页应用。
注意
根据自身体验,是否要参与有关使用 Angular 创建 Office 加载项的文章? 可以在 GitHub 中参与本文 ,或通过在存储库中提交 问题 来提供反馈。
有关使用 Angular 框架生成的 Office 加载项示例,请参阅使用 Angular 生成的 Word 样式检查加载项。
安装 TypeScript 类型定义
打开 Node.js 窗口,并在命令行中输入以下内容。
npm install --save-dev @types/office-js
引导必须位于 Office.initialize
在调用 Office JavaScript API 的任何页面上,代码必须首先将函数分配给 Office.initialize
。 Office 在初始化 Office JavaScript 库后立即调用此函数。 如果没有初始化代码,则函数体只能是空的“”{}
符号,但不得使 Office.initialize
函数保持未定义状态。 有关详细信息,请参阅 初始化 Office 加载项。
必须在分配给 Office.initialize
的函数内调用Angular引导代码。 这可确保 Office JavaScript 库首先初始化。 以下是演示如何执行该操作的简单示例。 此代码应位于项目的 main.ts 文件中。
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';
Office.initialize = function () {
const platform = platformBrowserDynamic();
platform.bootstrapModule(AppModule);
};
将 Office 对话框 API 与 Angular
Office 外接程序对话框 API 使外接程序能够在非模式对话框中打开页面,该对话框与main页交换信息,该页面通常位于任务窗格中。
displayDialogAsync 方法采用指定应在对话框中打开的页面的 URL 的参数。 外接程序可以有一个单独的 HTML 页面 (不同于要传递给此参数的基页) ,也可以在 Angular 应用程序中传递路由的 URL。
请务必记住,如果传递路由,对话框会创建一个具有其自己的执行上下文的新窗口。 基本页及其所有初始化和引导代码将在新上下文中再次运行,且任何变量都将被设置为对话框中的初始值。 此方法在对话框中启动单页应用程序的第二个实例。 更改对话框中变量的代码不会更改相同变量的任务窗格版本。 同样,对话框具有自己的会话存储 (Window.sessionStorage 属性) ,该属性无法从任务窗格中的代码访问。
触发 UI 更新
在Angular应用中,UI 有时不会更新。 这是因为部分代码在 Angular 区域外运行。 解决方案将代码放在该区域中,如下面的示例所示。
import { NgZone } from '@angular/core';
export class MyComponent {
constructor(private zone: NgZone) { }
myFunction() {
this.zone.run(() => {
// The codes that need update the UI.
});
}
}
使用可观测
Angular 使用 RxJS (Reactive Extensions for JavaScript),而 RxJS 引入了 Observable
和 Observer
对象来实现异步处理。 本部分简要介绍了如何使用 Observables
。 有关详细信息,请参阅官方 RxJS 文档。
Observable
在某种程度上类似一个 Promise
对象 - 它立即从异步调用返回,但它可能在以后才能进行解析。 不过,Promise
是一个值(可以是一个数组对象),而 Observable
是对象数组(可能仅有一个成员)。 这可使代码调用 对象上的 concat
,如 map
、filter
和 Observable
。
推送而不是拉取
代码“拉取” Promise
对象(通过将其分配到变量),而 Observable
对象将其值“推送”到订阅Observable
的对象。 订阅服务器是 Observer
对象。 推送体系结构的优势是,随着时间的推移,新成员可以添加到 Observable
数组。 添加了新成员后,订阅 Observer
的所有 Observable
对象都将收到一条通知。
Observer
配置为使用 函数处理每个新对象 (称为“next”对象) 。 (它还配置为响应错误和完成通知。有关 example.) 因此, Observable
可以在比 Promise
对象更广泛的方案中使用对象,请参阅下一部分。 例如,除了从 AJAX 调用返回 Observable
外,还可以通过返回 Promise
Observable
的方式从事件处理程序返回 ,例如文本框的“已更改”事件处理程序。 每当用户在框中输入文本时,所有订阅 Observer
的对象都会立即使用最新文本或应用程序的当前状态作为输入做出反应。
等到所有异步调用完成
如果想要确保仅当一组 Promise
对象的每个成员解析后运行撤消,请使用 Promise.all()
方法。
myPromise.all([x, y, z]).then(
// TODO: Callback logic goes here.
)
若要使用 Observable
对象执行同一操作,请使用 Observable.forkJoin() 方法。
const source = Observable.forkJoin([x, y, z]);
const subscription = source.subscribe(
x => {
// TODO: Callback logic goes here.
},
err => console.log('Error: ' + err),
() => console.log('Completed')
);
使用 Ahead-of-Time (AOT) 编译器编译 Angula r应用程序
应用程序性能是影响用户体验的最重要方面之一。 可以在构建时使用 Angular Ahead-of-Time (AOT) 编译器编译应用程序来优化 Angular 应用程序。 它可将所有源代码(HTML 模板和 TypeScript)转换为高效的 JavaScript 代码。 如果使用 AOT 编译器编译应用程序,则运行时不会发生其他编译,从而加快 HTML 模板的呈现和异步请求。 此外,应用程序的总体大小将减小,因为 Angular 编译器无需包含在可分发应用程序中。
若要使用 AOT 编译器,请将 --aot
添加到 ng build
或 ng serve
命令:
ng build --aot
ng serve --aot
注意
若要了解有关 Angular Ahead-of-Time (AOT) 编译器的详细信息,请参阅官方指南。
支持 Trident Webview 控件
较旧的 Office 客户端使用 Internet Explorer 11 提供的 Trident Webview 控件,如 Office 外接程序使用的浏览器和 Webview 控件中所述。如果外接程序需要支持这些 Office 版本,需要考虑几个特定于Angular注意事项。
Angular取决于几个window.history
Api。 这些 API 在 Trident Web 视图中不起作用。 当这些 API 不起作用时,加载项可能无法正常工作,例如,它可能会加载空白任务窗格。 为了缓解此问题,Office.js 将这些 API 设置为 null。 但是,如果要动态加载 Office.js,AngularJS 可能会在 Office.js 之前加载。 在这种情况下,应通过将以下代码添加到外接程序的“index.html”页来禁用 window.history
API。
<script type="text/javascript">window.history.replaceState=null;window.history.pushState=null;</script>
如果外接程序支持基于 Trident 的浏览器控件,则需要使用 哈希位置策略 而不是默认 路径位置策略。 路径位置策略需要 Trident 不提供的 HTML5 支持。