五、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文件,找到如下代碼: - 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);
- }
復(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)搜索的方法: - /**
- * 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;
- }
復(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: - /**
- * 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));
- }
- });
- }
-
復(fù)制代碼
當(dāng)搜索到合適的模板后,可以單擊按鈕,調(diào)用setOoxml()方法,將其插入到當(dāng)前word文檔中: - applyTemplate(template: WordTemplateInfo) {
- this.wordDocument.setOoxml(template.TemplateContent);
- }
復(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的地址。
|