摘要:之前項目中導出價格表是由后端實現,前端只需要調用接口下載word即可,后來業務改變比較大,word模版需要一直改動,后端改起來相對麻煩,后來直接前端自己定義模版,實現下載word文檔。
一、需要安裝的依賴
1、docxtemplater
介紹:docxtemplater是一種郵件合並工具,它以編程方式使用,處理條件、循環,並且可以擴展為表格、HTML、圖像等。
安裝方法:cnpm i docxtemplater@^3.9.1
2、FileSaver
介紹:FileSaver.js 是在客戶端保存文件的解決方案,非常適合需要生成文件,或者保存不應該發送到外部服務器的敏感信息的應用。
安裝方法:cnpm i file-saver@^1.3.8
3、jszip
介紹:jszip是一個用於創建、讀取和編輯.zip文件的JavaScript庫,且API的使用也很簡單。
安裝方法:cnpm i jszip@^2.6.1
4、jszip-utils
介紹:jszip-utils是與jszip一起使用的跨瀏覽器的工具庫
安裝方法:cnpm i jszip-utils@^0.0.2
二、創建word模版
介紹:根據自己的業務需求創建需要導出的word模版,變量數據使用{變量名}代替,表格內容數據需要使用{#參數名}開始{/參數名}結尾,具體如下圖:

注意點:1.模板文件使用vue-cli2的時候,放在static目錄下。使用vue-cli3的時候,放在public目錄下。
2.文件須以docx結尾。
不然可能出現的問題:提示Uncaught Error: Corrupted zip: missing 7124 bytes.
vue-cli3示例位置如圖:

三、html代碼編寫
定義下載事件downloadprice
<div class="download” @click="downloadprice">下載價格表</div>
四、script代碼編寫
1.使用的頁面中導入需要的插件:
import Docxtemplater from 'docxtemplater'; import { saveAs } from 'file-saver'; import JSZip from 'jszip'; import JSZipUtils from 'jszip-utils';
2.定義接口數據(這里為定義好的數據,正常情況下通過接口獲取需要在word文檔上展示的數據):
data() {
return {
// 導出價格表全部信息
exportPriceObj: {
actualPayFee: '179.55',
deliveryFee: '0.00',
discountActualFee: '179.55',
discountFee: '9.45',
discountRatio: '95',
nickName: '張三',
retailTotalFee: '0.00',
totalFee: '189.00',
},
// 導出價格表商品信息
exportPriceListOne: [
{
productColor: '白色',
productName: '0909測試商品',
productNo: 1,
productSize: '4XL(58)',
productSkuId: 'teydnkn',
sellingPrice: '10.00',
},
{
productColor: '白色',
productName: '1955測試商品',
productNo: 2,
productSize: 'XL(52)',
productSkuId: 'teydoja',
sellingPrice: '40.00',
}
],
}
}
3.下載word文檔點擊事件方法:
// 下載價格表 downloadprice() { let _this = this; // 判斷有無附加商品來選擇word模版 // 讀取並獲得模板文件的二進制內容 JSZipUtils.getBinaryContent('pricenew.docx', function(error, content) { console.log('-----', content); // input.docx是模板。我們在導出的時候,會根據此模板來導出對應的數據 // 拋出異常 if (error) { throw error; } // 創建一個JSZip實例,內容為模板的內容 let zip = new JSZip(content); console.log('+++++', zip); // 創建並加載docxtemplater實例對象 let doc = new Docxtemplater(); console.log('/////', doc); doc.loadZip(zip); console.log('=====', doc); // 設置模板變量的值 doc.setData({ // 導出價格表全部信息 ..._this.exportPriceObj, // 導出價格表商品信息 tableone: _this.exportPriceListOne, }); try { // 用模板變量的值替換所有模板變量 doc.render(); } catch (error) { // 拋出異常 let e = { message: error.message, name: error.name, stack: error.stack, properties: error.properties }; console.log(JSON.stringify({ error: e })); throw error; } // 生成一個代表docxtemplater對象的zip文件(不是一個真實的文件,而是在內存中的表示) let out = doc.getZip().generate({ type: 'blob', mimeType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' }); // 將目標文件對象保存為目標類型的文件,並命名 saveAs(out, _this.exportPriceObj.nickName + '的價格表.docx'); }); },
4.點擊下載后可能會出現的問題:
一、提示Uncaught Error: Corrupted zip: missing 7124 bytes.
錯誤方法如圖:

可能產生的原因是:1.模版文件word放置的位置獲取不到;
2.word文檔格式出現錯誤;
解決方法:1.模板文件使用vue-cli2的時候,放在static目錄下。使用vue-cli3的時候,放在public目錄下。
2.文件須以docx結尾。
正確方法如圖:

二、提示Uncaught Error: Can't find end of central directory : is this a zip file ?
錯誤方法如圖:

可能產生的原因是:1.你項目里面引用了mockjs文件,它的原理是重寫了XMLHttpRequest,導致你上報插件找不到對應的方法;
解決方法:上線時把項目中引入的mock注釋掉,// import '@/mock';
原理分析:mockjs是一個模擬后台接口的JS庫,它的原理是重寫了XMLHttpRequest,它可以在接口沒出來時非常方便的模擬數據,上線之后 不引用它即可。一般上報插件中會使用原生XMLHttpRequest,而原生XMLHttpRequest已被mockjs覆蓋找不到相應的方法,所以會 出錯。除了mockjs之外,zonejs、oboejs、fetchjs也有自己的的XMLHttpRequest庫,請慎用。
正確方法如圖:

三、提示 End of data reached (data length = 0, asked index = 4). Corrupted zip ?
錯誤方法如圖:

可能產生的原因:1.你項目上傳上去的word文件為空文件;
解決方法:1.請檢查你上傳到服務器的文件大小是否正確,如果字節為空或者字節大小不對,請替換一個正確的word文件上去;
四、其他問題等
請檢查你下載文件方法是否存在緩存,查詢方法如下:
304代表有緩存

200代表沒有

解決方法:
JSZipUtils.getBinaryContent('warehouse.docx?random=' + Math.random(), function(error, content) {
在引用文件時在文件后面添加一個隨機數
五、導出結果
導出結果如圖:

有問題歡迎留言,帶上問題和代碼截圖,看到后第一時間回復幫忙解答,謝謝!
