五、Word Add-In开发 有了API,就可以开发Add-In部分了。开篇说到,Add-In实际上是一个Web App,通过JavaScript操作Office文档对象,具体到这个项目来说,就是使用异步的js去查询、上传、搜索存在服务器上的模板文件,并动态的对当前Word文档进行操作。 微软在Github上开源了这个JavaScript API:https://github.com/OfficeDev/Office-js-docs_zh-cn/tree/staging, 相关文档:https://msdn.microsoft.com/zh-cn/library/office/fp142185.aspx 开发步骤可参考:https://github.com/OfficeDev/Office-js-docs_zh-cn/blob/staging/docs/get-started/create-and-debug-office-add-ins-in-visual-studio.md
下面来开发Add-In部分。
1.新建Add-In项目在解决方案上点击右键,添加一个Word Web外接程序:
添加完成后,多了两个项目:
其中一个是清单文件,带Web后缀的就是Web App了。
2.设置manifest.xml清单文件是非常重要的一个文件,描述加载项的所有设置。这个文件是自动生成的,但需要我们手动修改一些地方。好在文件中都有注释,所以修改还比较容易:
最重要的是修改SourceLocation这个节点,这个地址设置的是Web App托管的位置。在Web端开发并部署后,要将这个节点改为正确的位置才能发布。下面这个节点也要改掉。
3.Web App分析
可以先运行一下这个模板试试,直接F5:
点击此处就可以调出这个插件:
会自动打开Word并加载这个插件,文档中的文本就是插件插入的。那么是哪里的代码起作用的呢? 打开Home.js文件,找到如下代码: - function loadSampleData() {
- // Run a batch operation against the Word object model.
- Word.run(function (context) {
- // Create a proxy object for the document body.
- var body = context.document.body;
- // Queue a commmand to clear the contents of the body.
- body.clear();
- // Queue a command to insert text into the end of the Word document body.
- body.insertText(
- "This is a sample text inserted in the document",
- Word.InsertLocation.end);
- // Synchronize the document state by executing the queued commands, and return a promise to indicate task completion.
- return context.sync();
- })
- .catch(errorHandler);
- }
复制代码
这里的Word就是JavaScript API提供的对象,可以方便的对当前文档内容进行操作。这样思路就有了,可以通过JavaScript动态去调用Web API获取查询结果,将查询到的文档内容插入到当前文档中,就实现了最初的目的。同时还可以将当前文档的内容保存为模板上传到服务器上进行分享,一个完整功能的sample已经呼之欲出了。
4.使用Angular
我们使用最新的Angular4来开发前端页面。当然如果使用JQuery的话也可以,但现在已经有点out了不是吗?使用Angular可以快速开发一个MVVM架构的单页面WebApp,非常适合这个需求。 这个demo的部分代码参考微软开源的一个项目:https://github.com/OfficeDev/Office-Add-in-UX-Design-Patterns-Code
Angular上手曲线还是有点陡的,官方给出了Angular CLI工具,可以快速搭建一个Angular应用。首先安装TypeScript: npm install -g typescript
然后安装Angular CLI:https://github.com/angular/angular-cli npm install -g @angular/cli
运行以下命令创建一个Angular项目: ng new WordTemplateHelperSource
然后使用cd WordTemplateHelperSource 命令转到项目目录,运行以下命令: npm install
这个命令会安装ng项目所需的依赖,如果安装不成功,建议切换成淘宝npm镜像进行安装。 使用以下命令运行ng项目: ng serve
可以在Chorme浏览器中浏览http://localhost:4200来查看效果:
注意如果在IE中浏览是不正常的,这个问题我们到最后一节再给出解决办法。 为什么不直接在WordTemplateHelperWeb建呢?因为Angular应用还要进行打包,会在项目目录下生成dist目录,这才是正式要运行的部分。所以等开发完成后,将生成的dist目录内的文件拷到WordTemplateHelperWeb就可以了。
在开发Angular的过程中,推荐使用VS Code,对TypeScript和Angular的支持都非常好。 因为本篇文章不是Angular的开发教程,所以Angular的具体知识这里就不展开详述了,感兴趣的话可以自行下载Github代码运行即可。
5.添加操作Word文件的service
为了操作Word文件,我们需要将其封装成服务。使用以下命令添加一个service: ng g service services\word-document\WordDocument
这样会在app目录中的相应路径中生成一个名为WordDocumentService的服务。与此类似,生成其他的几个service。其中主要的几个方法如下: 查询搜索的方法: - /**
- * search
- *
- * @param {string} keyword
- * @returns {Promise<ResponseResultInfo<Array<WordTemplateInfo>>>}
- *
- * @memberOf WordTemplateApiService
- */
- searchWordTemplateList(keyword: string): Promise<ResponseResultInfo<Array<WordTemplateInfo>>> {
- let url = `${AppGlobal.getInstance().server}/SearchWordTemplateList?keyword=${keyword}`;
- let promise = this.httpService.get4Json<ResponseResultInfo<Array<WordTemplateInfo>>>(url);
- return promise;
- }
复制代码
这样可以得到服务器上存储的文档模板,实际是以Ooxml格式保存的string。 对于这个sample来说,使用Office JavaScript API并没有太难的东西,主要用到了两个方法:getOoxml()和insertOoxml(),前者可以读取当前word文档的Ooxml格式,后者可以设置当前word文档的Ooxml格式。Ooxml就是Office2007之后版本使用的格式,如docx这种。
原API提供的都是callback函数,为了使用方便我将其封装成Promise: - /**
- * get the ooxml of the doc
- *
- *
- * @memberOf WordDocumentService
- */
- getOoxml() {
- // Run a batch operation against the Word object model.
- return Word.run(function (context) {
- // Create a proxy object for the document body.
- var body = context.document.body;
- // Queue a commmand to get the HTML contents of the body.
- var bodyOOXML = body.getOoxml();
- // Synchronize the document state by executing the queued commands,
- // and return a promise to indicate task completion.
- // return context.sync().then(function () {
- // console.log("Body HTML contents: " + bodyHTML.value);
- // return bodyHTML.value;
- // });
- return context.sync().then(() => { return bodyOOXML.value });
- })
- .catch(function (error) {
- console.log("Error: " + JSON.stringify(error));
- if (error instanceof OfficeExtension.Error) {
- console.log("Debug info: " + JSON.stringify(error.debugInfo));
- }
- return "";
- });
- }
- /**
- * set the ooxml of the doc
- *
- * @param {string} ooxml
- *
- * @memberOf WordDocumentService
- */
- setOoxml(ooxml: string) {
- // Run a batch operation against the Word object model.
- Word.run(function (context) {
- // Create a proxy object for the document body.
- var body = context.document.body;
- // Queue a commmand to insert OOXML in to the beginning of the body.
- body.insertOoxml(ooxml, Word.InsertLocation.replace);
- // Synchronize the document state by executing the queued commands,
- // and return a promise to indicate task completion.
- return context.sync().then(function () {
- console.log('OOXML added to the beginning of the document body.');
- });
- })
- .catch(function (error) {
- console.log('Error: ' + JSON.stringify(error));
- if (error instanceof OfficeExtension.Error) {
- console.log('Debug info: ' + JSON.stringify(error.debugInfo));
- }
- });
- }
-
复制代码
当搜索到合适的模板后,可以单击按钮,调用setOoxml()方法,将其插入到当前word文档中: - applyTemplate(template: WordTemplateInfo) {
- this.wordDocument.setOoxml(template.TemplateContent);
- }
复制代码
这样就完成了应用模板的功能。
如果要实现将当前文档的内容保存为模板上传到服务器上,就可以调用getOoxml()方法得到当前文档的Ooxml格式文本,上传到服务器保存即可。至于其他的加为收藏、添加为机构模板、设置为个人模板等都是设置模板属性更新了,具体代码不再赘述。
还有一点需要注意的是,开发的时候,这里的服务器地址要写刚才我们开发的ASP.NET Core的地址。
|