Office中國(guó)論壇/Access中國(guó)論壇

 找回密碼
 注冊(cè)

QQ登錄

只需一步,快速開(kāi)始

返回列表 發(fā)新帖
查看: 2560|回復(fù): 3
打印 上一主題 下一主題

[Office插件] 【轉(zhuǎn)】Office365開(kāi)發(fā)系列——開(kāi)發(fā)一個(gè)全功能的Word Add-In

[復(fù)制鏈接]

點(diǎn)擊這里給我發(fā)消息

跳轉(zhuǎn)到指定樓層
1#
發(fā)表于 2018-11-26 12:02:56 | 只看該作者 回帖獎(jiǎng)勵(lì) |倒序?yàn)g覽 |閱讀模式

2016年10月我參加了在北京舉行的DevDays Asia 2016 - Office 365應(yīng)用開(kāi)發(fā)”48小時(shí)黑客馬拉松“,我開(kāi)發(fā)的一個(gè)Word Add-In Demo——WordTemplateHelper獲得了二等獎(jiǎng)。在會(huì)場(chǎng)有幸結(jié)識(shí)了陳希章老師,在與陳老師的交流中受益良多,得知陳老師在準(zhǔn)備一個(gè)Office解決方案系列后,我想把這個(gè)Demo的開(kāi)發(fā)過(guò)程簡(jiǎn)要介紹給大家,以支持陳老師的無(wú)私奉獻(xiàn),也希望更多的開(kāi)發(fā)者參與到Office365的開(kāi)發(fā)中來(lái)。


Office相關(guān)開(kāi)發(fā)主要可以參考這個(gè)地址:https://dev.office.com/getting-started

本篇文章主要介紹其中的Office加載項(xiàng)開(kāi)發(fā),即Office Add-ins:https://msdn.microsoft.com/ZH-CN/library/office/jj220082.aspx


一、什么是Office Add-Ins

什么是Office Add-ins呢?在陳老師的上一篇文章中,對(duì)整個(gè)Office發(fā)展歷史都進(jìn)行了梳理,我個(gè)人的理解就是,開(kāi)發(fā)者可以在Office提供的平臺(tái)上,對(duì)Office做出一定的擴(kuò)展以實(shí)現(xiàn)各種功能,比如之前錄制的宏,寫(xiě)的VBS的腳本,某種意義上都可以看做是Office的Add-ins。當(dāng)然這只是個(gè)人理解,不一定準(zhǔn)確。目前的Office Add-Ins只支持Office2013以后的版本,開(kāi)發(fā)方式也和以前的VBS有了很大的區(qū)別。


現(xiàn)在的Office Add-ins結(jié)構(gòu)是這樣的:


一個(gè)Office Add-in其實(shí)是一個(gè)Web App,可以將其部署在任意位置,它可以在一個(gè)Office應(yīng)用程序中運(yùn)行。有一個(gè)manifest.xml清單文件用來(lái)指定該Web App如何來(lái)呈現(xiàn),包括定義Web App 的URL。當(dāng)Office加載這個(gè)Add-in時(shí),實(shí)際上是提供了一個(gè)瀏覽器的環(huán)境,來(lái)運(yùn)行指定的Web App。也就是說(shuō),現(xiàn)在開(kāi)發(fā)一個(gè)Office Add-in,其實(shí)跟開(kāi)發(fā)網(wǎng)頁(yè)程序差不多,這對(duì)熟悉html+JavaScript+css的前端開(kāi)發(fā)人員是非常容易上手的。微軟提供了豐富的JavaScript API來(lái)對(duì)Office進(jìn)行操作,能實(shí)現(xiàn)什么就取決于開(kāi)發(fā)者的想象力了。


一個(gè)Word Add-In的實(shí)例:


二、Word Template Helper需求分析

我在得知有這個(gè)活動(dòng)時(shí),并沒(méi)有想好要做什么,一直到坐上赴京的高鐵,才慢慢有了一個(gè)想法,這個(gè)想法也是來(lái)自平時(shí)的工作需要。在工作中經(jīng)常要撰寫(xiě)大量的文檔,如各種軟件需求規(guī)格說(shuō)明書(shū)、公函、文書(shū)、操作手冊(cè)等,這些文檔都有規(guī)定的格式,一般情況下我是將一些已經(jīng)寫(xiě)好的Word文檔保存在一個(gè)文件夾里當(dāng)做模板,下次寫(xiě)這種文檔的時(shí)候復(fù)制一份,刪刪減減的再改。為何不自己寫(xiě)個(gè)程序,將這些具有固定模式的文檔作為Word模板呢?雖然Word也有自己的模板,但實(shí)際上是非常有限的,并不能完全滿足我們的需要。如果這個(gè)功能做成一個(gè)模板商店,大家可以自由上傳、分享各自的模板,也許會(huì)方便許多。


Word自帶的模板是這樣的:


這些通用模板對(duì)專(zhuān)業(yè)性比較強(qiáng)的工作來(lái)說(shuō)是遠(yuǎn)遠(yuǎn)不夠的。Word Template Helper的效果是這樣的:


主意有了,那么就來(lái)看一下如何實(shí)現(xiàn)。我參加活動(dòng)時(shí)的項(xiàng)目托管在碼云上,為了寫(xiě)這篇文章,我重新梳理了這個(gè)小demo,在Github上建了一個(gè)項(xiàng)目,并嘗試使用最新的.NET Core來(lái)實(shí)現(xiàn)后臺(tái)API部分。接下來(lái)就跟我一起動(dòng)手吧。


三、項(xiàng)目架構(gòu)

首先分析一下該項(xiàng)目的結(jié)構(gòu)。文檔的模板數(shù)據(jù),如模板標(biāo)題、屬性等,需要保存在數(shù)據(jù)庫(kù)里,還需要一個(gè)Web API項(xiàng)目提供數(shù)據(jù),Office Add-in為一個(gè)純前端項(xiàng)目,使用Angular2框架,采用異步調(diào)用Web API的數(shù)據(jù),實(shí)現(xiàn)搜索、加載模板等功能。插件的UI使用微軟提供的Fabric UI。整個(gè)項(xiàng)目的技術(shù)棧如下

所示:


至于文檔的實(shí)體——Word文檔,是以Word格式文件存儲(chǔ)還是直接保存在數(shù)據(jù)庫(kù)中呢?如果是正式項(xiàng)目的話,當(dāng)然是保存在云存儲(chǔ)中是最合適的,但對(duì)于一個(gè)sample來(lái)說(shuō),直接保存在數(shù)據(jù)庫(kù)中也未嘗不可。因?yàn)槭菂⒓娱_(kāi)發(fā)馬拉松,怎么快怎么來(lái)吧。包括ORM框架也是,只是為了快速實(shí)現(xiàn)采用的方式,不是最佳實(shí)踐。


這個(gè)sample的開(kāi)發(fā)環(huán)境配置如下:

Windows 10 x64,

VS 2017(請(qǐng)確保安裝了Office開(kāi)發(fā)工具)

VS Code

Node.js v7.10.0

NPM v4.2.0

ASP.NET Core 1.1



本帖子中包含更多資源

您需要 登錄 才可以下載或查看,沒(méi)有帳號(hào)?注冊(cè)

x
分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏 分享分享 分享淘帖 訂閱訂閱

點(diǎn)擊這里給我發(fā)消息

2#
 樓主| 發(fā)表于 2018-11-26 12:17:35 | 只看該作者
四、Web API開(kāi)發(fā)

VS2017已經(jīng)正式發(fā)布了,我使用最新的.NET Core來(lái)實(shí)現(xiàn)Web API層。


1.新建項(xiàng)目

新建一個(gè)空白解決方案,命名為WordTemplateHelpe,然后在其中添加一個(gè)ASP.NET Core項(xiàng)目:


選擇Web API:



2.安裝EF Core

在nuget管理器中搜索安裝一下幾個(gè)Nuget包:

Microsoft.EntityFrameworkCore.SqlServer:EF Core SQL Server

Microsoft.EntityFrameworkCore.Tools:EF命令行工具

Microsoft.EntityFrameworkCore.Tools.DotNet:EF Core命令行工具




3.建立Models

目前最新的EF都推薦使用Code First模式,即直接寫(xiě)Model,EF框架會(huì)自動(dòng)創(chuàng)建所需的數(shù)據(jù)庫(kù)。如果習(xí)慣DB First的話,也有一個(gè)很好的工具推薦:EntityFramework-Reverse-POCO-Code-First-Generator:https://visualstudiogallery.msdn.microsoft.com/ee4fcff9-0c4c-4179-afd9-7a2fb90f5838



可以直接在VS的擴(kuò)展與更新里下載。這個(gè)工具可以很方便的根據(jù)數(shù)據(jù)庫(kù)生成所需的實(shí)體類(lèi)。

首先添加一個(gè)模板類(lèi)型的枚舉:   

  1.     /// <summary>
  2.     /// 類(lèi)型
  3.     /// </summary>
  4.     public enum TemplateType
  5.     {
  6.         /// <summary>
  7.         /// Private
  8.         /// </summary>
  9.         [Description("Private")]
  10.         Private = 0,
  11.         /// <summary>
  12.         /// Public
  13.         /// </summary>
  14.         [Description("Public")]
  15.         Public = 1,
  16.         /// <summary>
  17.         /// Organization
  18.         /// </summary>
  19.         [Description("Organization")]
  20.         Organization = 2,

  21.     }
復(fù)制代碼


添加一個(gè)模板類(lèi):

  1. public class PrivateTemplateInfo
  2.     {
  3.         ///<summary>
  4.         /// Id
  5.         ///</summary>
  6.         public string Id { get; set; }

  7.         ///<summary>
  8.         /// User Id
  9.         ///</summary>
  10.         public string UserId { get; set; }

  11.         ///<summary>
  12.         /// Template Id
  13.         ///</summary>
  14.         public string TemplateId { get; set; }

  15.         ///<summary>
  16.         /// Create Time
  17.         ///</summary>
  18.         public DateTime CreateTime { get; set; }
  19.     }
復(fù)制代碼


因?yàn)檫需要組織機(jī)構(gòu)模板、用戶收藏等幾個(gè)表,這里就不寫(xiě)了,可參考Github上的示例。


4.創(chuàng)建數(shù)據(jù)庫(kù)上下文

有了Model后,需要指定哪些實(shí)體包含在數(shù)據(jù)模型中。添加一個(gè)Data文件夾,在其中創(chuàng)建一個(gè)名為WordTemplateContext.cs的文件:

  1.     public class WordTemplateContext:DbContext
  2.     {
  3.         public WordTemplateContext(DbContextOptions<WordTemplateContext> options) : base(options)
  4.         {

  5.         }

  6.         public DbSet<WordTemplateInfo> WordTemplateInfoes { get; set; }
  7.         public DbSet<UserFavoriteInfo> UserFavoriteInfoes { get; set; }
  8.         public DbSet<PrivateTemplateInfo> PrivateTemplateInfoes { get; set; }
  9.         public DbSet<OrganizationTemplateInfo> OrganizationTemplateInfoes { get; set; }

  10.     }
復(fù)制代碼

這樣就為每個(gè)實(shí)體創(chuàng)建了一個(gè)DbSet,對(duì)應(yīng)數(shù)據(jù)庫(kù)中的表,實(shí)體對(duì)應(yīng)表中的行。


5.使用依賴(lài)注入注冊(cè)上下文

ASP.NET Core默認(rèn)實(shí)現(xiàn)了依賴(lài)注入。要把剛才建立的WordTemplateContext注冊(cè)成服務(wù),需要在Startup.cs中添加以下代碼:

  1.         public void ConfigureServices(IServiceCollection services)
  2.         {
  3.             
  4.             // Add framework services.
  5.             services.AddDbContext<WordTemplateContext>(options =>
  6.             options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
  7.             services.AddMvc();
  8.         }
復(fù)制代碼


注意要添加using Microsoft.EntityFrameworkCore;不然會(huì)找不到UseSqlServer方法。

數(shù)據(jù)庫(kù)連接字符串在appsettings.json中配置:

  1. {
  2.   "ConnectionStrings": {
  3.     "DefaultConnection": "Server=.;User ID=sa;Password=12QWasZX;Initial Catalog=WordTemplate;"
  4.   },
  5.   "Logging": {
  6.     "IncludeScopes": false,
  7.     "LogLevel": {
  8.       "Default": "Warning"
  9.     }
  10.   }
  11. }
復(fù)制代碼


這里使用了LocalDb,用于測(cè)試。當(dāng)需要正式部署時(shí),這里需要更改為正式數(shù)據(jù)庫(kù)服務(wù)器的地址及用戶名密碼。



6.初始化數(shù)據(jù)庫(kù)

下面使用命令行初始化數(shù)據(jù)庫(kù)。在Data目錄下新建一個(gè)DbInitializer類(lèi),輸入以下方法:

  1.     public static class DbInitializer
  2.     {
  3.         public static void Initialize(WordTemplateContext context)
  4.         {
  5.             context.Database.EnsureCreated();

  6.             //TODO
  7.             context.SaveChanges();
  8.         }
  9.     }
復(fù)制代碼


確保數(shù)據(jù)被創(chuàng)建。然后修改Startup.cs文件中的Configure方法:

  1.         public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, WordTemplateContext context)
  2.         {
  3.             loggerFactory.AddConsole(Configuration.GetSection("Logging"));
  4.             loggerFactory.AddDebug();

  5.             app.UseMvc();
  6.             DbInitializer.Initialize(context);
  7.         }
復(fù)制代碼


7.創(chuàng)建API接口

現(xiàn)在寫(xiě)個(gè)Controller看看。在Controller文件夾中添加一個(gè)控制器:



這里可以使用依賴(lài)注入,將數(shù)據(jù)庫(kù)上下文注入進(jìn)來(lái):

  1.     [Produces("application/json")]
  2.     [Route("api/WordTemplate/[action]")]
  3.     public class WordTemplateController : Controller
  4.     {
  5.         private readonly WordTemplateContext _context;

  6.         public WordTemplateController(WordTemplateContext context)
  7.         {
  8.             _context = context;
  9.         }
復(fù)制代碼


我們以一個(gè)搜索模板的api為例:

  1.   [HttpGet]
  2.         public async Task<ResponseResultInfo<List<WordTemplateInfo>>> SearchWordTemplateList(string keyword)
  3.         {
  4.             ResponseResultInfo<List<WordTemplateInfo>> respResult = new ResponseResultInfo<List<WordTemplateInfo>>();
  5.             try
  6.             {

  7.                 List<WordTemplateInfo> list = await _context.WordTemplateInfoes.Where(x => x.Type == TemplateType.Public && x.Name.Contains(keyword)).OrderByDescending(x => x.CreateTime).ToListAsync();
  8.                 respResult.IsSuccess = true;
  9.                 respResult.Result = list;
  10.                 return respResult;

  11.             }
  12.             catch (Exception ex)
  13.             {
  14.                 //LogHelper.ErrorWriteLine("Something wrong. The exception message::{0}", ex);
  15.                 respResult.IsSuccess = false;
  16.                 respResult.Message = string.Format("Something wrong. The exception message::{0}", ex.Message);
  17.                 return respResult;
  18.             }
  19.         }
復(fù)制代碼


命令行轉(zhuǎn)到項(xiàng)目目錄,運(yùn)行以下命令


dotnet run

可以使用前端調(diào)試?yán)鱌ostman來(lái)測(cè)試:


API項(xiàng)目運(yùn)行的具體地址需要記一下,后面做Add-In的時(shí)候要用到。具體代碼請(qǐng)參考Github。


8.允許跨域訪問(wèn)

為了支持Add-in能夠跨域訪問(wèn)我們的接口,還需要安裝以下的庫(kù):


然后在Startup.cs的ConfigureServices方法中添加以下代碼:

  1. #region 跨域
  2.             services.AddCors(options =>
  3.             options.AddPolicy("AllowCrossDomain",
  4.             builder => builder.WithOrigins().AllowAnyMethod().AllowAnyHeader().AllowAnyOrigin().AllowCredentials())
  5.             );
  6.             
  7.             #endregion
復(fù)制代碼


在需要跨域的WordTemplateController上添加一行:


[EnableCors("AllowCrossDomain ")]


這樣api就可以支持跨域訪問(wèn)了。




本帖子中包含更多資源

您需要 登錄 才可以下載或查看,沒(méi)有帳號(hào)?注冊(cè)

x

點(diǎn)擊這里給我發(fā)消息

3#
 樓主| 發(fā)表于 2018-11-26 14:22:00 | 只看該作者
五、Word Add-In開(kāi)發(fā)

有了API,就可以開(kāi)發(fā)Add-In部分了。開(kāi)篇說(shuō)到,Add-In實(shí)際上是一個(gè)Web App,通過(guò)JavaScript操作Office文檔對(duì)象,具體到這個(gè)項(xiàng)目來(lái)說(shuō),就是使用異步的js去查詢(xún)、上傳、搜索存在服務(wù)器上的模板文件,并動(dòng)態(tài)的對(duì)當(dāng)前Word文檔進(jìn)行操作。

微軟在Github上開(kāi)源了這個(gè)JavaScript API:https://github.com/OfficeDev/Office-js-docs_zh-cn/tree/staging

相關(guān)文檔:https://msdn.microsoft.com/zh-cn/library/office/fp142185.aspx

開(kāi)發(fā)步驟可參考:https://github.com/OfficeDev/Office-js-docs_zh-cn/blob/staging/docs/get-started/create-and-debug-office-add-ins-in-visual-studio.md


下面來(lái)開(kāi)發(fā)Add-In部分。


1.新建Add-In項(xiàng)目

在解決方案上點(diǎn)擊右鍵,添加一個(gè)Word Web外接程序:



添加完成后,多了兩個(gè)項(xiàng)目:



其中一個(gè)是清單文件,帶Web后綴的就是Web App了。


2.設(shè)置manifest.xml

清單文件是非常重要的一個(gè)文件,描述加載項(xiàng)的所有設(shè)置。這個(gè)文件是自動(dòng)生成的,但需要我們手動(dòng)修改一些地方。好在文件中都有注釋?zhuān)孕薷倪比較容易:



最重要的是修改SourceLocation這個(gè)節(jié)點(diǎn),這個(gè)地址設(shè)置的是Web App托管的位置。在Web端開(kāi)發(fā)并部署后,要將這個(gè)節(jié)點(diǎn)改為正確的位置才能發(fā)布。下面這個(gè)節(jié)點(diǎn)也要改掉。



3.Web App分析

可以先運(yùn)行一下這個(gè)模板試試,直接F5:



點(diǎn)擊此處就可以調(diào)出這個(gè)插件:



會(huì)自動(dòng)打開(kāi)Word并加載這個(gè)插件,文檔中的文本就是插件插入的。那么是哪里的代碼起作用的呢?

打開(kāi)Home.js文件,找到如下代碼:

  1.     function loadSampleData() {
  2.         // Run a batch operation against the Word object model.
  3.         Word.run(function (context) {
  4.             // Create a proxy object for the document body.
  5.             var body = context.document.body;

  6.             // Queue a commmand to clear the contents of the body.
  7.             body.clear();
  8.             // Queue a command to insert text into the end of the Word document body.
  9.             body.insertText(
  10.                 "This is a sample text inserted in the document",
  11.                 Word.InsertLocation.end);

  12.             // Synchronize the document state by executing the queued commands, and return a promise to indicate task completion.
  13.             return context.sync();
  14.         })
  15.         .catch(errorHandler);
  16.     }
復(fù)制代碼


這里的Word就是JavaScript API提供的對(duì)象,可以方便的對(duì)當(dāng)前文檔內(nèi)容進(jìn)行操作。這樣思路就有了,可以通過(guò)JavaScript動(dòng)態(tài)去調(diào)用Web API獲取查詢(xún)結(jié)果,將查詢(xún)到的文檔內(nèi)容插入到當(dāng)前文檔中,就實(shí)現(xiàn)了最初的目的。同時(shí)還可以將當(dāng)前文檔的內(nèi)容保存為模板上傳到服務(wù)器上進(jìn)行分享,一個(gè)完整功能的sample已經(jīng)呼之欲出了。


4.使用Angular

我們使用最新的Angular4來(lái)開(kāi)發(fā)前端頁(yè)面。當(dāng)然如果使用JQuery的話也可以,但現(xiàn)在已經(jīng)有點(diǎn)out了不是嗎?使用Angular可以快速開(kāi)發(fā)一個(gè)MVVM架構(gòu)的單頁(yè)面WebApp,非常適合這個(gè)需求。

這個(gè)demo的部分代碼參考微軟開(kāi)源的一個(gè)項(xiàng)目:https://github.com/OfficeDev/Office-Add-in-UX-Design-Patterns-Code


Angular上手曲線還是有點(diǎn)陡的,官方給出了Angular CLI工具,可以快速搭建一個(gè)Angular應(yīng)用。首先安裝TypeScript:

npm install -g typescript

然后安裝Angular CLI:https://github.com/angular/angular-cli

npm install -g @angular/cli

運(yùn)行以下命令創(chuàng)建一個(gè)Angular項(xiàng)目:

ng new WordTemplateHelperSource



然后使用cd WordTemplateHelperSource 命令轉(zhuǎn)到項(xiàng)目目錄,運(yùn)行以下命令:

npm install

這個(gè)命令會(huì)安裝ng項(xiàng)目所需的依賴(lài),如果安裝不成功,建議切換成淘寶npm鏡像進(jìn)行安裝。

使用以下命令運(yùn)行ng項(xiàng)目:

ng serve

可以在Chorme瀏覽器中瀏覽http://localhost:4200來(lái)查看效果:



注意如果在IE中瀏覽是不正常的,這個(gè)問(wèn)題我們到最后一節(jié)再給出解決辦法。

為什么不直接在WordTemplateHelperWeb建呢?因?yàn)锳ngular應(yīng)用還要進(jìn)行打包,會(huì)在項(xiàng)目目錄下生成dist目錄,這才是正式要運(yùn)行的部分。所以等開(kāi)發(fā)完成后,將生成的dist目錄內(nèi)的文件拷到WordTemplateHelperWeb就可以了。


在開(kāi)發(fā)Angular的過(guò)程中,推薦使用VS Code,對(duì)TypeScript和Angular的支持都非常好。

因?yàn)楸酒恼虏皇茿ngular的開(kāi)發(fā)教程,所以Angular的具體知識(shí)這里就不展開(kāi)詳述了,感興趣的話可以自行下載Github代碼運(yùn)行即可。


5.添加操作Word文件的service

為了操作Word文件,我們需要將其封裝成服務(wù)。使用以下命令添加一個(gè)service:

ng g service services\word-document\WordDocument

這樣會(huì)在app目錄中的相應(yīng)路徑中生成一個(gè)名為WordDocumentService的服務(wù)。與此類(lèi)似,生成其他的幾個(gè)service。其中主要的幾個(gè)方法如下:

查詢(xún)搜索的方法:

  1. /**
  2.      * search
  3.      *
  4.      * @param {string} keyword
  5.      * @returns {Promise<ResponseResultInfo<Array<WordTemplateInfo>>>}
  6.      *
  7.      * @memberOf WordTemplateApiService
  8.      */
  9.     searchWordTemplateList(keyword: string): Promise<ResponseResultInfo<Array<WordTemplateInfo>>> {
  10.         let url = `${AppGlobal.getInstance().server}/SearchWordTemplateList?keyword=${keyword}`;
  11.         let promise = this.httpService.get4Json<ResponseResultInfo<Array<WordTemplateInfo>>>(url);
  12.         return promise;
  13.     }
復(fù)制代碼


這樣可以得到服務(wù)器上存儲(chǔ)的文檔模板,實(shí)際是以O(shè)oxml格式保存的string。

對(duì)于這個(gè)sample來(lái)說(shuō),使用Office JavaScript API并沒(méi)有太難的東西,主要用到了兩個(gè)方法:getOoxml()和insertOoxml(),前者可以讀取當(dāng)前word文檔的Ooxml格式,后者可以設(shè)置當(dāng)前word文檔的Ooxml格式。Ooxml就是Office2007之后版本使用的格式,如docx這種。


原API提供的都是callback函數(shù),為了使用方便我將其封裝成Promise:

  1. /**
  2.      * get the ooxml of the doc
  3.      *
  4.      *
  5.      * @memberOf WordDocumentService
  6.      */
  7.     getOoxml() {
  8.         // Run a batch operation against the Word object model.
  9.         return Word.run(function (context) {

  10.             // Create a proxy object for the document body.
  11.             var body = context.document.body;

  12.             // Queue a commmand to get the HTML contents of the body.
  13.             var bodyOOXML = body.getOoxml();

  14.             // Synchronize the document state by executing the queued commands,
  15.             // and return a promise to indicate task completion.
  16.             // return context.sync().then(function () {
  17.             //     console.log("Body HTML contents: " + bodyHTML.value);
  18.             //     return bodyHTML.value;
  19.             // });
  20.             return context.sync().then(() => { return bodyOOXML.value });
  21.         })
  22.             .catch(function (error) {
  23.                 console.log("Error: " + JSON.stringify(error));
  24.                 if (error instanceof OfficeExtension.Error) {
  25.                     console.log("Debug info: " + JSON.stringify(error.debugInfo));
  26.                 }
  27.                 return "";
  28.             });
  29.     }

  30.     /**
  31.      * set the ooxml of the doc
  32.      *
  33.      * @param {string} ooxml
  34.      *
  35.      * @memberOf WordDocumentService
  36.      */
  37.     setOoxml(ooxml: string) {
  38.         // Run a batch operation against the Word object model.
  39.         Word.run(function (context) {

  40.             // Create a proxy object for the document body.
  41.             var body = context.document.body;

  42.             // Queue a commmand to insert OOXML in to the beginning of the body.
  43.             body.insertOoxml(ooxml, Word.InsertLocation.replace);

  44.             // Synchronize the document state by executing the queued commands,
  45.             // and return a promise to indicate task completion.
  46.             return context.sync().then(function () {
  47.                 console.log('OOXML added to the beginning of the document body.');
  48.             });
  49.         })
  50.             .catch(function (error) {
  51.                 console.log('Error: ' + JSON.stringify(error));
  52.                 if (error instanceof OfficeExtension.Error) {
  53.                     console.log('Debug info: ' + JSON.stringify(error.debugInfo));
  54.                 }
  55.             });
  56.     }
復(fù)制代碼


當(dāng)搜索到合適的模板后,可以單擊按鈕,調(diào)用setOoxml()方法,將其插入到當(dāng)前word文檔中:

  1. applyTemplate(template: WordTemplateInfo) {
  2.     this.wordDocument.setOoxml(template.TemplateContent);
  3.   }
復(fù)制代碼



這樣就完成了應(yīng)用模板的功能。


如果要實(shí)現(xiàn)將當(dāng)前文檔的內(nèi)容保存為模板上傳到服務(wù)器上,就可以調(diào)用getOoxml()方法得到當(dāng)前文檔的Ooxml格式文本,上傳到服務(wù)器保存即可。至于其他的加為收藏、添加為機(jī)構(gòu)模板、設(shè)置為個(gè)人模板等都是設(shè)置模板屬性更新了,具體代碼不再贅述。


還有一點(diǎn)需要注意的是,開(kāi)發(fā)的時(shí)候,這里的服務(wù)器地址要寫(xiě)剛才我們開(kāi)發(fā)的ASP.NET Core的地址。




本帖子中包含更多資源

您需要 登錄 才可以下載或查看,沒(méi)有帳號(hào)?注冊(cè)

x

點(diǎn)擊這里給我發(fā)消息

4#
 樓主| 發(fā)表于 2018-11-26 14:31:00 | 只看該作者
6.使用Fabric UI

對(duì)于一個(gè)Office Add-in來(lái)說(shuō),具有簡(jiǎn)潔美觀、與Office統(tǒng)一的UI是必須的。微軟推薦使用Fabric UI來(lái)實(shí)現(xiàn)統(tǒng)一的界面樣式,詳見(jiàn):https://dev.office.com/fabric

這里提供了樣式、圖標(biāo)、設(shè)計(jì)規(guī)范等很多資源,甚至還提供了React版的組件,如果使用React開(kāi)發(fā)的話直接拿來(lái)用就可以了。這個(gè)demo是直接引用的style文件,配置在.angular-cli.json文件中:



應(yīng)用后就變成這樣子:




7.打包Add-in

剛才只是在一個(gè)新項(xiàng)目里開(kāi)發(fā)了一個(gè)靜態(tài)Web App,還要將其打包,復(fù)制到WordTemplateHelperWeb項(xiàng)目中。使用ng build –prod來(lái)打包Angular應(yīng)用。打包后的文件會(huì)輸出到dist目錄下:




注意還有一個(gè)需要注意的地方,如果僅這樣打包的話,是不支持IE瀏覽器的,但Office Add-In實(shí)際上內(nèi)置的瀏覽器就是IE內(nèi)核,所以我們需要做如下修改,找到src目錄中的polyfills.ts文件,將下面部分的注釋取消:





還要根據(jù)提示,運(yùn)行npm install命令安裝幾個(gè)必須的依賴(lài)。這樣才能在IE系列瀏覽器中正常運(yùn)行。再次運(yùn)行ng build –prod進(jìn)行打包。--prod參數(shù)的意義是以生產(chǎn)模式進(jìn)行build,這樣生成的代碼體積更小,運(yùn)行速度更快。


將WordTemplateHelperWeb項(xiàng)目中的原文件除了Web.config外,全部刪除。把dist目錄中的文件復(fù)制過(guò)來(lái)。

雖然本機(jī)開(kāi)發(fā)時(shí)可以直接調(diào)試運(yùn)行,但為了模擬真實(shí)的使用情況,我們把這個(gè)Web App也正式發(fā)布一下。如果我們有Azure或其他主機(jī)的話就直接部署到服務(wù)器上,現(xiàn)在只用本機(jī)IIS來(lái)承載這個(gè)Web App:



這樣該Add-In的地址就是:http://localhost/WordTemplateHelperWeb,

下面把a(bǔ)pi運(yùn)行起來(lái),進(jìn)入WordTemplateHelperApi目錄,運(yùn)行dotnet run命令:




這樣API項(xiàng)目的地址是:http://localhost:5000/api/

這兩個(gè)地址不要混淆。剛才在打包WebApp的時(shí)候也要注意,在common\app-global.ts文件中的api地址也要改成和實(shí)際api地址一樣的才可以:

  1.     /**
  2.      * api url
  3.      *
  4.      * @type {string}
  5.      * @memberOf AppGlobal
  6.      */
  7.     public server: string = "http://localhost:5000/api/WordTemplate";
復(fù)制代碼


現(xiàn)在打開(kāi)WordTemplateHelperManifest清單文件,修改如下位置:






這里填的是Add-In的地址,一定不要搞錯(cuò)了。


6.運(yùn)行測(cè)試

現(xiàn)在可以重新運(yùn)行Add-In項(xiàng)目了,將啟動(dòng)項(xiàng)目設(shè)置為WordTemplateHelper,運(yùn)行:




我們可以粘貼一個(gè)模板,并上傳到服務(wù)器上:




點(diǎn)擊Upload按鈕即可將當(dāng)前文檔作為模板上傳到服務(wù)器上分享。




搜索到相應(yīng)的模板后,點(diǎn)擊apply按鈕即可將模板內(nèi)容插入到當(dāng)前文檔。


我們可以搜索模板,添加自己的模板,并將模板內(nèi)容應(yīng)用到當(dāng)前文檔中。針對(duì)組織和個(gè)人還可以分別進(jìn)行管理,我的設(shè)想是,這個(gè)小插件能夠做成一個(gè)模板商店之類(lèi)的平臺(tái),用戶可以自由的交換彼此的文檔模板,并可以收藏、添加到本人組織的模板庫(kù)中等等。稍加擴(kuò)展就可以做成一個(gè)正式產(chǎn)品了。


7.載入加載動(dòng)畫(huà)

在頁(yè)面加載時(shí)可以加一個(gè)載入提示,使用戶體驗(yàn)更加友好。具體代碼可參考index.html中的css樣式。




六、小結(jié)

這篇文章拖了很久,去年的比賽,今年才把過(guò)程整理出來(lái),實(shí)在很想對(duì)陳老師說(shuō)一聲抱歉^_^。Office Add-In是一個(gè)比較新的開(kāi)發(fā)領(lǐng)域,跟以前的開(kāi)發(fā)方式有所不同,但熟悉前端的同學(xué)可以迅速進(jìn)入這個(gè)領(lǐng)域,實(shí)際上就是寫(xiě)網(wǎng)頁(yè)。這個(gè)實(shí)例從后端接口到前臺(tái)實(shí)現(xiàn),是一個(gè)比較完整的項(xiàng)目,希望對(duì)Office開(kāi)發(fā)有興趣的同學(xué)下載代碼研究一下,開(kāi)發(fā)出更加實(shí)用的Add-In。因?yàn)檫@個(gè)項(xiàng)目并沒(méi)有實(shí)際部署,所以沒(méi)有上傳到商店中。下載代碼的用戶請(qǐng)勿用于商業(yè)用途。特此說(shuō)明。


Github地址:https://github.com/yanxiaodi/WordTemplateHelper




轉(zhuǎn)載自CSDN 的 Long0801:
《Office365開(kāi)發(fā)系列——開(kāi)發(fā)一個(gè)全功能的Word Add-In  》






本帖子中包含更多資源

您需要 登錄 才可以下載或查看,沒(méi)有帳號(hào)?注冊(cè)

x
您需要登錄后才可以回帖 登錄 | 注冊(cè)

本版積分規(guī)則

QQ|站長(zhǎng)郵箱|小黑屋|手機(jī)版|Office中國(guó)/Access中國(guó) ( 粵ICP備10043721號(hào)-1 )  

GMT+8, 2025-7-17 00:33 , Processed in 0.103657 second(s), 28 queries .

Powered by Discuz! X3.3

© 2001-2017 Comsenz Inc.

快速回復(fù) 返回頂部 返回列表