工作中經常會遇到根據不同數據導出文檔的情況,現在我們就來看一下基于 docxtemplater 來導出word文檔的方法,使用起來非常便捷。
安裝依賴的插件
-- 安裝 docxtemplater
npm install docxtemplater pizzip --save
-- 安裝 jszip-utils
npm install jszip-utils --save
-- 安裝 jszip
npm install jszip --save
-- 安裝 FileSaver
npm install file-saver --save
下面簡單介紹一下這幾個插件的功能:
-
docxtemplater
:docxtemplate是一個從docx/pptx模板生成docx/pptx文檔的庫。語法包含變量替換、條件判斷、循環、列表循環、表格循環等,還包括圖片、html等模塊轉換。 -
jszip-utils
:jszip-utils是一個與 JSZip 一起使用的跨瀏覽器實用程序集合,詳細可參考 官網網址中的文檔。 -
jszip
: jszip是一個JavaScript類庫,用來操作.zip文件的工具,詳細可參考 官方網址 中的文檔。 -
file-saver
:file-saver是在客戶端保存文件的解決方案,非常適合需要生成文件或者保存不應該發送到外部服務器的敏感信息的應用,詳細用法可參考 官方網址 中的文檔。
創建exportFile.js(導出word方法)
- 引入依賴包
- 使用
jszip-utils
讀取并獲得模板文件的二進制內容 - 使用
PizZip
創建實例,內容為模板的內容 - 使用
docxtemplater
創建實例,并加載PizZip
創建的實例 - 使用
docxtemplater
創建實例設置導出數據,并用導出數據的值替換所有模板變量 - 生成一個代表docxtemplater對象的zip文件
- 使用
saveAs
將生成的zip文件對象保存為目標類型的文件,并命名
import PizZip from 'jszip';
import docxtemplater from 'docxtemplater';
import JSZipUtils from 'jszip-utils';
import { saveAs } from 'file-saver';
/**
* 導出word,支持圖片
* @param {Object} tempDocxPath 模板文件路徑
* @param {Object} wordData 導出數據
* @param {Object} fileName 導出文件名
*/
export const exportWord = (tempDocxPath, wordData, fileName) => {
// 讀取并獲得模板文件的二進制內容
JSZipUtils.getBinaryContent(tempDocxPath, function (error, content) {
if (error) {
throw error;
}
// 創建一個PizZip實例,內容為模板的內容
const zip = new PizZip(content);
// 創建并加載docxtemplater實例對象
const doc = new docxtemplater();
doc.loadZip(zip);
doc.setData(wordData);
try {
// 用模板變量的值替換所有模板變量
doc.render();
} catch (error) {
// 拋出異常
const e = {
message: error.message,
name: error.name,
stack: error.stack,
properties: error.properties
};
console.log(
JSON.stringify({
error: e
})
);
throw error;
}
// 生成一個代表docxtemplater對象的zip文件(不是一個真實的文件,而是在內存中的表示)
const out = doc.getZip().generate({
type: 'blob',
mimeType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
});
// 將目標文件對象保存為目標類型的文件,并命名
saveAs(out, fileName);
}
);
};
編寫word文檔模板,具體的寫法可以參考 docxtemplater demo 上的例子
下面列出幾中常見的 docxtemplater
語法
- 替換
js中的變量定義:
{title:'簡介'}
word模板文件中語法:
{title}
- 循環
js中的變量定義:
{
loop:[
{ name: "Windows", price: 100},
{ name: "Mac OSX", price: 200 },
{ name: "Ubuntu", price: 0 }
],
userGreeting: (scope) => {
return "The product is" + scope.name + ", price:" + scope.price;
},
}
word模板文件中語法:
循環{#loop}
{name}, {price}
// 匿名函數插槽用法
{userGreeting}
{/loop}
- 判斷
js中的變量定義:
{
hasKitty: true,
kitty: "Minie",
hasDog: false,
dog: "wangwang",
}
word模板文件中語法:
{#hasKitty}
Cat’s name: {kitty}
{/hasKitty}
{#hasDog}
Dog’s name: {dog}
{/hasDog}
- 圖片
js中的變量定義:
{
//文件路徑
image: '/logo.png',
}
word模板文件中語法:
{%image}
在組件中調用exportFile.js方法
import { exportWord } from '@/util/exportFile.js';
/**
* 參數1:模板文檔路徑
* 參數2:字段參數
* 參數3:輸出文檔
*/
const obj={
...
}
exportWord('template.docx' ,obj, '導出文件名.docx');
在這里關于模板文件的路徑 tempDocxPath
我們要著重說一下。
在使用的過程中應該有不少人會遇到這種報錯:Can't find end of central directory : is this a zip file ?
那這到底是什么原因導致的呢?
獲得模板文件的二進制內容的方法,JSZipUtils.getBinaryContent(path, option) 提供path和option兩個參數。我們來看一下path,前端開發最首先想到的可能是絕對路徑或者相對路徑,你可能還會用到@這個符號作為根目錄使用,但在這里你顯然不能這么用。
- 如果我們的模板文件為‘xxxx.docx’,那么我們的path應該為‘/xxxx.docx’。修改完這個地方之后,剩下的就是要知道你使用的vue-cli是版本2還是版本3。如果是2,則應該有一個static的文件夾,請見你的模板文件放入這個static文件夾中;如果是3,則有一個public文件夾,請將模板文件放入這個public文件夾中。
- 如果經過上面的修改依然報錯,那么你就要看一下你的項目是不是微應用項目或者在項目路徑上做了什么處理,如果是的話你需要根據項目目錄填寫xxxx.docx真正的路徑。