原理:需要將頁面中table導出一個word文件,在本地做好一個word模板,定義好變量,以這個模板文件為導出依賴,將后台獲取的變量添加進去。
需求:將“倫理審查批件”導出為word

導出word和pdf對實際工作的影響:
上一篇博客實現了前端導出pdf,但是后來發現,當意見內容特別多的時候,pdf分頁會有點問題:

而word會自動處理這種情況:

綜上,如果確定導出文件的高度在一頁內能搞定,那么用pdf會更簡單點,需要多頁的話還是用word更適合使用需求。
導出pdf的原理是 html2canvas 對頁面進行截圖,再用 jspdf 將截圖轉為 pdf,所以這種做法一定會導致多頁的時候出現上述問題,但是現在好像vue導出pdf大多數使用的都是這個方法,以后有時間再研究下其他的方法可以導出好看點的pdf。
操作步驟:
1、下載插件
npm i docxtemplater jszip-utils file-saver jszip@2.6.1
注意:jszip的版本是2.6.1,最新版的可能有問題,或者安裝 pizzip 替代 jszip
3、引入插件和定義導出函數
import docxtemplater from 'docxtemplater' import JSZipUtils from 'jszip-utils' import { saveAs } from 'file-saver' import JSZip from 'jszip'
exportWord: function() { let _this = this // 讀取並獲得模板文件的二進制內容 JSZipUtils.getBinaryContent('approvalNo.docx', function(error, content) { if (error) throw error // 拋出異常 let zip = new JSZip(content) // 創建一個JSZip實例,內容為模板的內容 let doc = new docxtemplater().loadZip(zip) // 創建並加載docxtemplater實例對象 doc.setData({ ..._this.approvalNoOrOpinionNoList }) // 設置模板變量的值 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, 'aaa.docx') }) }
注意:引入路徑和傳入到模板中的參數

4、定義按鈕點擊導出,實際導出效果:

報錯:
第一種:
Uncaught Error: Error: Can't find end of central directory : is this a zip file ? If it is, see http://stuk.github.io/jszip/documentation/howto/read_zip.html
at XMLHttpRequest.xhr.onreadystatechange

翻譯:
未捕獲的錯誤:錯誤:無法找到結束的中央目錄:這是一個zip文件嗎?如果是,請查看http://stuk.github.io/jszip/documentation/howto/read_zip.html
在XMLHttpRequest.xhr.onreadystatechange
解釋:················意思是說你路徑寫錯了
第二種:
Uncaught Error: InternalError: The filetype for this file could not be identified, is this file corrupted ?
at XMLHttpRequest.xhr.onreadystatechange

翻譯:
無法識別此文件的文件類型,此文件是否已損壞?
在XMLHttpRequest.xhr.onreadystatechange
解釋:················意思是說后綴名doc會有可能出問題,換成docx試試
頁面完整代碼:
<template>
<div class="approvalNo-or-opinionNo-list">
<el-button type="primary" size="small" @click="exportWord">點擊下載</el-button>
<div id="pdfDom">
<table cellspacing="0">
<caption>
倫理審查批件
</caption>
<tr>
<td class="key-name">批件號</td>
<td colspan="3">{{ approvalNoOrOpinionNoList.approvalNo }}</td>
</tr>
<tr>
<td class="key-name">項目名稱</td>
<td colspan="3">{{ approvalNoOrOpinionNoList.projectName }}</td>
</tr>
<tr>
<td class="key-name">項目來源</td>
<td colspan="3">{{ approvalNoOrOpinionNoList.sponsorName }}</td>
</tr>
<tr>
<td class="key-name">研究單位</td>
<td colspan="3">{{ approvalNoOrOpinionNoList.researchUnit }}</td>
</tr>
<tr>
<td class="key-name">主要研究者</td>
<td colspan="3">{{ approvalNoOrOpinionNoList.personName }}</td>
</tr>
<tr>
<td class="key-name">審查類別</td>
<td>{{ approvalNoOrOpinionNoList.taskStyle }}</td>
<td class="key-name">審查方式</td>
<td>{{ approvalNoOrOpinionNoList.taskType }}</td>
</tr>
<tr>
<td class="key-name">審查日期</td>
<td>{{ approvalNoOrOpinionNoList.auditDate }}</td>
<td class="key-name">審查地點</td>
<td>{{ approvalNoOrOpinionNoList.auditAddress }}</td>
</tr>
<tr>
<td class="key-name">審查委員</td>
<td colspan="3">{{ approvalNoOrOpinionNoList.auditCommittees }}</td>
</tr>
<tr>
<td class="key-name">批准文件</td>
<td colspan="3">見附件</td>
</tr>
<tr>
<td colspan="4" class="options">
{{ approvalNoOrOpinionNoList.auditRemark }}
</td>
</tr>
<tr>
<td class="key-name">年度/定期<br />跟蹤審查頻率</td>
<td colspan="3">{{ approvalNoOrOpinionNoList.frequency }}</td>
</tr>
<tr>
<td class="key-name">有效期</td>
<td colspan="3">{{ approvalNoOrOpinionNoList.effectiveStartDate }} 至 {{ approvalNoOrOpinionNoList.effectiveEndDate }}</td>
</tr>
<tr>
<td class="key-name">聯系人與聯系電話</td>
<td colspan="3">{{ approvalNoOrOpinionNoList.sponsorContacts }} {{ approvalNoOrOpinionNoList.sponsorTel }}</td>
</tr>
<tr>
<td class="key-name">倫理委員會</td>
<td colspan="3">{{ approvalNoOrOpinionNoList.ethicsCommittee }}</td>
</tr>
<tr>
<td class="key-name">主任簽名</td>
<td colspan="3">{{ approvalNoOrOpinionNoList.directorAutograph }}</td>
</tr>
<tr>
<td class="key-name">日期</td>
<td colspan="3">{{ approvalNoOrOpinionNoList.todayDate }}</td>
</tr>
</table>
</div>
</div>
</template>
<script>
import docxtemplater from 'docxtemplater'
import JSZipUtils from 'jszip-utils'
import { saveAs } from 'file-saver'
import JSZip from 'jszip'
export default {
data() {
return {}
},
props: {
approvalNoOrOpinionNoList: {
type: Object,
default: {}
}
},
methods: {
exportWord: function() {
let _this = this
// 讀取並獲得模板文件的二進制內容
JSZipUtils.getBinaryContent('approvalNo.docx', function(error, content) {
if (error) throw error // 拋出異常
let zip = new JSZip(content) // 創建一個JSZip實例,內容為模板的內容
let doc = new docxtemplater().loadZip(zip) // 創建並加載docxtemplater實例對象
doc.setData({ ..._this.approvalNoOrOpinionNoList }) // 設置模板變量的值
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, 'aaa.docx')
})
}
}
}
</script>
<style lang="scss">
.approvalNo-or-opinionNo-list {
height: 350px;
overflow-y: auto;
padding-bottom: 20px;
border-bottom: 1px solid #ccc;
> #pdfDom {
table {
text-align: center;
border-bottom: 1px solid #ccc;
width: 93%;
margin: 0 auto;
font-family: '楷體', '楷體_GB2312';
caption {
font-size: 16px;
text-align: center;
line-height: 46px;
color: #333;
font-weight: bold;
}
td {
width: 25%;
height: 32px;
color: #666;
border-left: 1px solid #ccc;
border-top: 1px solid #ccc;
padding: 0 6px;
}
td:last-child {
border-right: 1px solid #ccc;
}
.key-name {
color: #333;
font-weight: 600;
}
.options {
padding: 10px;
text-align: justify;
text-indent: 2em;
}
}
}
}
</style>
前端vue以數據流方式導出word----借助 jquery
