项目需要导出word,于是乎又是查阅资料。然后自己写。
参考链接
https://github.com/evilc0des/docxtemplater-image-module-free
https://www.jianshu.com/p/b3622d6f8d98
Vue导出Word
配置word模板
新建一个word文档,名字随便取只要对应就好,我创建的是一个template.docx。下面是我的配置,简单解释一下:
1. {#wordList}包裹一个循环对象{/wordList}
2. 对象中有serviceImgUrl,title,pageNumber属性
3. wordList:[{ pageNumber: ‘’, title: ‘’, serviceImgUrl: ‘’ }]
下载
// 这些插件要了解的自己查阅资料
npm i docxtemplater pizzip -S
npm i jszip-utils -S
npm i jszip -S
npm i file-saver -S
npm i -S docxtemplater-image-module-free
npm i pizzip -S
导入
import PizZip from 'pizzip'
import docxtemplater from 'docxtemplater'
import JSZipUtils from 'jszip-utils'
import { saveAs } from 'file-saver'
import { Loading } from 'element-ui';
点击导出按钮
这里需要先了解导出的word数据,上面有提到是一个数组对象wordList:[{ pageNumber: ‘’, title: ‘’, serviceImgUrl: ‘’ }]
// 点击导出文档按钮
handleExportWord() {
this.wordList = []
if(!this.chooseCollectWordList.length) return this.$message.warning('请勾选需要导出的文件')
this.loading = Loading.service({
lock: true,
text: '拼命打包中',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
});
this.chooseCollectWordList.forEach((item, i) => {
this.wordList.push({ pageNumber: item.pageNumber.toString(), title: item.title, serviceImgUrl: '' })
this.getBase64Image(item.serviceImgUrl, this.wordList, i)
})
// 刚开始在这里写
// this.exportWord()
},
服务器图片转Base64
这一步需要后端支持,这个问题是我们后端解决的,我也不太清楚,具体可以自行查阅资料。但是要保证图片地址能转成base64。
getBase64Image(src, wordList, i) {
let _this = this
var image = new Image();
// image.src = src + '?v=' + Math.random(); // 处理缓存
image.src = src
image.setAttribute("crossOrigin", '*'); // 支持跨域图片
image.onload = async function() {
let base64 = ""
var canvas = document.createElement("canvas");
canvas.width = image.width;
canvas.height = image.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(image, 0, 0, image.width, image.height);
base64 = await canvas.toDataURL("image/png"); // 可选其他值 image/jpeg
wordList[i].serviceImgUrl = base64
// 这里调用的原因是防止serviceImgUrl还未转换成base64就调用exportWord接口
if(i == _this.wordList.length - 1) {
_this.exportWord()
}
return base64;
}
// 图片加载失败警告
image.onerror = function() {
wordList[i].serviceImgUrl = ''
if(i == _this.wordList.length - 1) {
_this.exportWord()
return
}
}
},
base64转二进制
这个什么都不用改,直接复制粘贴
base64DataURLToArrayBuffer(dataURL) {
const base64Regex = /^data:image\/(png|jpg|svg|svg\+xml);base64,/;
if(!base64Regex.test(dataURL)) {
return false;
}
const stringBase64 = dataURL.replace(base64Regex, "");
let binaryString;
if(typeof window !== "undefined") {
binaryString = window.atob(stringBase64);
} else {
binaryString = new Buffer(stringBase64, "base64").toString("binary");
}
const len = binaryString.length;
const bytes = new Uint8Array(len);
for(let i = 0; i < len; i++) {
const ascii = binaryString.charCodeAt(i);
bytes[i] = ascii;
}
return bytes.buffer;
}
导出文档
exportWord() {
var ImageModule = require('docxtemplater-image-module-free');
const expressions = require("angular-expressions");
let _this = this;
// 读取并获得模板文件的二进制内容,放在项目中即可
// template.docx对应上面的word模板
JSZipUtils.getBinaryContent("template.docx", function(error, content) {
if(error) {
_this.loading.close();
_this.$message.error('出现未知错误')
console.log(error)
throw error;
};
expressions.filters.size = function(input, width, height) {
return {
data: input,
size: [width, height],
};
};
function angularParser(tag) {
const expr = expressions.compile(tag.replace(/’/g, "'"));
return {
get(scope) {
return expr(scope);
},
};
}
// 图片处理
let opts = {}
opts = { centered: false };
opts.getImage = function(chartId) {
return _this.base64DataURLToArrayBuffer(chartId);
}
opts.getSize = function() {
return [600, 350];
}
// 创建一个PizZip实例,内容为模板的内容
let zip = new PizZip(content);
// 创建并加载docxtemplater实例对象
let doc = new docxtemplater();
doc.attachModule(new ImageModule(opts));
doc.loadZip(zip).compile();
// 设置模板变量的值
// 使用doc.setData开发环境不会出现错误,生产环境就是他喵的要发疯,有几张图片就是导不出来。
// 这个问题是个毒瘤,害我解决了好久,幸好后面解决了。具体就是用doc.resolveData
/* doc.setData({
wordList: _this.wordList
}); */
doc.resolveData({
wordList: _this.wordList
}).then(() => {
// 用模板变量的值替换所有模板变量
doc.render();
// 生成一个代表docxtemplater对象的zip文件(不是一个真实的文件,而是在内存中的表示)
let out = doc.getZip().generate({
type: "blob",
mimeType:
"application/vnd.openxmlformats-officedocument.wordprocessingml.document"
});
// 将目标文件对象保存为目标类型的文件,并命名
_this.loading.close();
let date = new Date()
let fileName = "文件名称"
saveAs(out, `${fileName}.docx`);
}).catch((error) => {
_this.loading.close();
let e = {
message: error.message,
name: error.name,
stack: error.stack,
properties: error.properties
};
console.log(JSON.stringify({ error: e }));
throw error;
})
});
},
代码写出来了,如果出现什么问题可以参考上面的第一个链接,第一个链接都没有做出来,那就只能自行查阅了。我的导出是没什么问题的。