最近遇到一個(gè)需求-->報(bào)表word下載,網(wǎng)上查了很多資料,發(fā)現(xiàn)其實(shí)無(wú)外乎就兩種吼畏,一種是無(wú)模板html節(jié)點(diǎn)直接轉(zhuǎn)word,一種是固定模板填充值的word,恰好我的業(yè)務(wù)報(bào)表是動(dòng)態(tài)的非固定格式的嘁灯,因此我的處理方式是第一種泻蚊。
類(lèi)型一、html無(wú)模板轉(zhuǎn)word
框架:vue
插件:jquery + file-saver + html-docx-js
邏輯:通過(guò)jquery$('節(jié)點(diǎn)')
獲取需要轉(zhuǎn)為word文檔的html節(jié)點(diǎn)丑婿,借助file-saver提供的saveAs方法和html-docx-js提供的asBlob方法轉(zhuǎn)換我們?cè)O(shè)置好的html即可
核心代碼:
import htmlDocx from "html-docx-js/dist/html-docx";
import { saveAs } from "file-saver";
import $ from "jquery";
function exportWord(dom, fileName) {
setTimeout(() => {
let htmlStr = `
<!DOCTYPE html>
<html lang="en">
<body style="font-family:方正仿宋_GBK;mso-ascii-font-family:'Times New Roman'">
${dom.html()}
</body>
</html>
`;
saveAs( htmlDocx.asBlob(htmlStr, { orientation: "landscape" }), fileName );
}, 200);
}
如果你需要轉(zhuǎn)換的html不涉及圖片(包括echarts)性雄,那么上面的轉(zhuǎn)換就已經(jīng)完全可以了,另外fileName的后綴建議使用‘.docx’而不是‘.doc’
如果有圖片(包括echarts)需要轉(zhuǎn)換為word羹奉,我們需要用線上圖片替代本地的圖片秒旋,這樣圖片才能完美兼容Microsoft Office Word和WPC Office兩個(gè)軟件 ,如果不替代的話Microsoft Office Word不兼容尘奏、WPC Office部分版本不兼容滩褥,關(guān)于本地圖片不兼容的問(wèn)題,個(gè)人猜測(cè)是因?yàn)閎ase64 不能完美兼容word軟件炫加,但是二進(jìn)制可以做到完美兼容瑰煎。
線上替代本地圖片具體操作邏輯如下:
第一步:通過(guò)Jquery方法.clone()
復(fù)制需要轉(zhuǎn)換為word的html節(jié)點(diǎn) (注意:我們后續(xù)的一系列都是操作的此節(jié)點(diǎn))
第二步:獲取圖片節(jié)點(diǎn),將圖片轉(zhuǎn)換為base64上傳至服務(wù)器 (注意:echarts可直接通過(guò)自帶的方法.getConnectedDataURL({ type: "png" })
獲取base64)
第三步:獲取圖片線上地址
第四步:創(chuàng)建節(jié)點(diǎn)<img style="margin:0 auto" width="600" src="'+ 圖片的線上地址 +" />
(注意:img的src必須是全路徑K仔ⅰ>频椤! 所以如果接口返回的地址不是全路徑赋铝,需要自行拼接為全路徑)
第五步:通過(guò)jquery方法.html()
將第四步創(chuàng)建好的節(jié)點(diǎn)去替換之前第二步獲取到的圖片節(jié)點(diǎn)至此圖片替換就全部完成了
代碼如下:(下面例中圖片是echarts插勤,如果是img自行百度如何轉(zhuǎn)換base64哦)
import htmlDocx from "html-docx-js/dist/html-docx";
import { saveAs } from "file-saver";
import $ from "jquery";
function exportWord(dom, fileName) {
setTimeout(async() => {
// 1、復(fù)制
let DOM=dom.clone();
// 2革骨、獲取echarts節(jié)點(diǎn)
const echart = DOM.find(".my-echarts");
for (let i = 0; i < echart.length; i++) {
var curEchart = this.$echarts.getInstanceByDom(echart[i]);
if (curEchart) {
//獲取base64
var base = curEchart.getConnectedDataURL({ type: "png" });
//base64轉(zhuǎn)File(這塊需不需要轉(zhuǎn)看項(xiàng)目的后端农尖,因?yàn)槲业暮蠖俗髁松蟼鹘涌诠潭ㄒ?guī)定,只能傳file對(duì)象良哲,所以需要base64轉(zhuǎn)file)
var file = this.dataURLtoFile(base, "test.png");
console.log(file);
//上傳并獲取線上地址
let { data } = await apiUploadFormData(file); //接口上傳
console.log(123123, data);
//創(chuàng)建新節(jié)點(diǎn)
var _img = $(
'<img style="margin:0 auto" width="600" src="' + data.url + '"/>'
);
//替換
$(echart[i]).html(_img);
}
}
let htmlStr = `
<!DOCTYPE html>
<html lang="en">
<body style="font-family:方正仿宋_GBK;mso-ascii-font-family:'Times New Roman'">
${DOM.html()}
</body>
</html>
`;
saveAs( htmlDocx.asBlob(htmlStr, { orientation: "landscape" }), fileName );
}, 200);
}
//base64轉(zhuǎn)File
function dataURLtoFile(dataurl, fileName) {
var arr = dataurl.split(","),
mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]),
n = bstr.length,
u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new File([u8arr], fileName, { type: mime });
},
//圖片上傳接口請(qǐng)求處理(在這里不能使用盛卡,相信每個(gè)小可愛(ài)都看得懂這塊想表達(dá)啥)
import request from '@/utils/request'
export const apiUploadFormData = (file) => {
let formData = new FormData()
formData.append("file", file);
return request.post('圖片上傳接口地址',formData)
}
以上,Html轉(zhuǎn)word就全部完成了
題外話一:關(guān)于word 個(gè)性化樣式
如果想設(shè)置個(gè)性化的樣式筑凫,建議使用jquery方法
.find()
查找節(jié)點(diǎn)直接添加style屬性.attr('style','樣式')
設(shè)置滑沧,即找到需要操作的dom元素,dom添加行內(nèi)樣式即可巍实,注意:添加行內(nèi)樣式時(shí)滓技,需要注意代碼執(zhí)行順序,避免有些行內(nèi)樣式被覆蓋
// dom是需要轉(zhuǎn)換為word的html節(jié)點(diǎn)
dom.find('.title').attr('style','font-weight: bold;margin: 10px 0;text-align:center')
題外話二:關(guān)于word table樣式(按需取用)
我使用的ui庫(kù)是element棚潦,然后我的表格是基于el-table二次封裝好的組件令漂,它在被轉(zhuǎn)換成js原生table表格后,不僅樣式很丑,而且thead和tbody還被識(shí)別成了2個(gè)表格洗显,雖然視覺(jué)上不影響外潜,但是還是存在thead和tbody單元格無(wú)法對(duì)齊的現(xiàn)象
表格說(shuō)明:我的表格全是后端返回表頭和表格數(shù)據(jù)的動(dòng)態(tài)表格
解決方法:復(fù)制原thead內(nèi)容,插入到tbody成為tbody第一行挠唆,然后刪除thead
//處理所有表格
dom.find(".my-global-table").each((key, value) => {
//處理單個(gè)表格
//1处窥、獲取表格thead內(nèi)容
let thArr = [];
dom
.find(`.my-global-table:eq(${key}) th div.cell`)
.each((_key, value) => {
let m = value.innerHTML;
let str = `<td><div class="cell">${m}</div></td>`;
thArr.push(str);
});
let thStr = `<tr>${thArr.join("")}</tr>`;
//2、插入新表頭
if(thArr.length!==0){
$(thStr).insertBefore(
dom.find(`.my-global-table:eq(${key}) tr:eq(1)`)
);
}
//3玄组、刪除舊表頭
dom
.find(`.my-global-table:eq(${key}) .el-table__header-wrapper`)
.remove();
//4滔驾、如果表格本身有表頭但是無(wú)數(shù)據(jù),我們需要重新添加表頭回去
let Length = dom.find(`.my-global-table:eq(${key}) tr`).length;
if (Length == 0 && thArr.length!==0) {
dom
.find(`.my-global-table:eq(${key}) tbody`)
.html(`<tbody>${thStr}</tbody>`);
}
});
console.log(8888, dom);
//統(tǒng)一設(shè)置所有表格樣式
dom
.find(".the-text-table .my-global-table")
.attr("style", "text-align:center;margin:0 auto;width:80%"); //表格
dom
.find(".my-global-table tr")
.attr(
"style",
"height:44px;vertical-align:middle;padding-left:4px;width:80%"
); //表格
類(lèi)型二俄讹、固定模板轉(zhuǎn)word
我沒(méi)有實(shí)際操作過(guò)哆致,不過(guò)看下面兩篇參考應(yīng)該足以解決這個(gè)需求吧
參考一
參考二