vue导出Word(包含echarts)
纯小白一步步填坑去学vue怎么导出Word
因为公司做的是阅卷系统,最近要开发一个新功能,老板说的是可以导出一本像书似的可打印的PDF,因为成绩报表里面都是学生成绩的分析图也就是echarts还有各种表格,无法确定其长度,多以导出PDF最终到了成功导出但我的echarts都被拦腰切断这步不了了之,实在是做不出来,最后考虑到老师下载后还要编辑,采取了导出Word的形式,不多废话,一步步开始。
导入安装包
第一步当然是下载导入包啦,需要下载如下的几个安装包:
// 下载
npm install docxtemplater pizzip --save
npm install jszip-utils --save
npm install jszip --save
npm install file-saver --save
//在需要导出Word的vue文件导入
import JSZipUtils from 'jszip-utils';
import docxtemplater from 'docxtemplater';
import { saveAs } from 'file-saver';
import PizZip from 'pizzip';
创建模板
在本地创建一个docx也就是Word文档,放入我们的项目中,我用的是脚手架2,所以放在static下,百度说用3的话需要放在public下,然后我们编写需要的Word底层的模板。其实语法在docxtemplater 官网写的非常的清楚还明白(其实我第一次去官网看,都不知道去哪儿看语法规则,害)这里是官网的地址可以参考(https://docxtemplater.readthedocs.io/en/latest/)去例子那里看就非常清楚。下面我简单介绍几个常用的注意的:
这张图是我简单写的一个例子,因为命名过多,我就胡乱用拼音代替了,哈哈
要想成功输出数据,需要有数组包裹 {#字段名}开始 {/字段名}结束,但凡数据是存在数组中的 就必须用数组名称给包裹起来,否则就会输出undefined,图片的话我用的是base64格式,输出需要用{%字段名}这样写{%%字段名}这样是使图片居中。因为我的数据中存在大量的echarts图表,图片的问题稍后说,回到文本内容上,要是有表格输出的话,我们需要在Word中自己建立表格,然后拿出数据去渲染。大家可以对比我的Word还有我的data数据就能明白。
echart图片处理
因为我的报表中几乎都是echarts,所以输出到Word中是以图片形式的,我们先用echarts自带的功能getDataURL()会直接得到base64的图片格式,这是代码:
var that = this;
var img = new Image();
img.src = myline.getDataURL({
pixelRatio: 2,// 导出的图片分辨率比例,默认为 1。
backgroundColor: '#fff'// 导出的图片背景色,默认使用 option 里的 backgroundColor
});
that.wordData.fenduanList.fdUrl= img.src;
//wordData是包裹全部要输出的在Word文档中的最外层的数组名称
给图片赋值的时候一定要记住是=img.src,这里我最开始做的时候以为=img就OK了 但怎么也导不出来 最后才想通要的是地址而不是个图片。
除了echarts自带的方法,我最开始导出PDF时还接触到一个 叫做html2Canvas的插件,这个主要是把vue前端页面转化为base64格式的图片,即所见即所得,因为我的项目存在大量的echart图表而且很多都是我循环出来的,所以用上面的办法没有找到办法循环得到base64图片,所以采用这种插件,如下是代码:
import html2Canvas from 'html2canvas';//下载并导入包
getCanvas(){
//this.$refs.ss 就是标记我图片的大框div区域
for(let j = 0 ; j <this.$refs.ss.length;j++){
html2Canvas(this.$refs.ss[j],{
allowTaint: false,//允许 canvas 污染
useCORS: true, //允许图片跨域
}).then((canvas)=>{
this.sydArr.push(canvas.toDataURL('image/png', 1.0));
//这里得到的就是一个循环出来的base64图片数组
});
}
},
这里是打印出来的循环数组的样式
然后最后一步就是导出Word了
导出Word
上代码:
//这里是官网写的应该是处理图片的代码,照着写就行,没动过
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;
},
// 导出word
exportWord() {
//这里要引入处理图片的插件,下载docxtemplater后,引入的就在其中了
var ImageModule = require('docxtemplater-image-module-free');
var that = this;
//这里是我的Word路径,在static文件下
JSZipUtils.getBinaryContent("../../static/word.docx", function (error, content) {
if (error) {
throw error
};
let opts = {}
opts.centered = true;
opts.fileType = "docx";
opts.getImage = (tag)=> {
return that.base64DataURLToArrayBuffer(tag);
}
opts.getSize = ()=>{
return [600, 400]//这里可更改输出的图片宽和高
}
let zip = new PizZip(content);
let doc = new docxtemplater();
doc.attachModule(new ImageModule(opts));
doc.loadZip(zip);
doc.setData({
...that.wordData//我的最外层包裹一切要导出的数据名称
});
try {
doc.render()
} catch (error) {
var e = {
message: error.message,
name: error.name,
stack: error.stack,
properties: error.properties,
}
console.log(JSON.stringify({
error: e
}));
throw error;
}
var out = doc.getZip().generate({
type: "blob",
mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
})
saveAs(out, "成绩报表.docx")
})
},
然后就没有然后了,成功导出,这是我的样例:
封面,页码,页眉页脚,目录的话也可以自己直接在Word模板中填好,导出时就会自动生成了,但目录的功能虽然可实现,但不能动态的刷新成新目录,目前只能导出后用户自己更新目录,这点让我很困扰,如果有解决的办法,欢迎告知。奥,对了如果总报如下的错误,就去看看自己的Word模板上的标签名包没包住,尽量的对齐书写标签名称。
这是我的第一篇博客,很是激动,来自一个毕业一年,工作一年但觉得自己就是废物的不能说胖仙女程序猿,哈哈哈。