用docxtemplater插件,前端实现html导出word文档(可导出文字、表格、图片)
下面我用的是vue框架,用其他框架同理,只要这个插件能兼容就行
官方文档https://docxtemplater.com/
参考地址https://www.cnblogs.com/zmh-980509/p/15480113.html
一、下载插件并引入
// 下载名字与导入名字相同,照着npm/yarn
import JSZipUtils from 'jszip-utils';
import PizZip from 'pizzip';
import docxtemplater from 'docxtemplater'; //导出word文档的插件
import { saveAs } from 'file-saver';
import ImageModule from 'docxtemplater-image-module-free'; //导出图片才需要这个插件
二、设置模板
需要在public路径下设置一个word的标准模板文件(也可以在其它路径,后面导入正确即可),内容例如:
需要导出的变量格式如下,其中,字体样式,如字体大小加粗等可以直接在word表中设置;图片宽高需在js里设置:
普通变量 {params}
循环 {#List} {params} {/List}
图片 {%imgUrl}
三、主要内容
主要用到的方法,注意要点基本都在备注里面。
exportWord() {
JSZipUtils.getBinaryContent('/docTemp/xxxxx.docx', (error, content) => {
//'/docTemp/xxxxx.docx'为模板的地址
const zip = new PizZip(content);
let doc = new docxtemplater();
doc.loadZip(zip);
//处理图片 开始
const opts = {};
// opts.centered = true; // 图片居中
opts.fileType = 'docx';
opts.getImage = chartId => {
return this.base64DataURLToArrayBuffer(chartId);
};
opts.getSize = function(byteLength, url, name) {
// 可根据name不同分别设置图片的宽高
//if (name == 'lastPanoUrl' || name == 'panoUrl') {
// return [280, 180];
//} else if (name == 'posUrl') {
// return [300, 230];
//} else {
// return [180, 110];
//}
return [200, 120];
};
let imageModule = new ImageModule(opts);
doc.attachModule(imageModule);
//处理图片 结束
});
//自定义导入表中的变量
let baseInfo = {
params: 'xxxx',
List: [{}, {}, {}],
imgUrl: '' //图片需为base64地址
};
doc.setData(baseInfo); //baseInfo为导入表中的变量,键值都可以自己定义
try {
doc.render();
} catch (error) {
const e = {
message: error.message,
name: error.name,
stack: error.stack,
properties: error.properties
};
throw error;
}
const out = doc.getZip().generate({
type: 'blob',
mimeType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
});
saveAs(out, '无居民海岛无人机巡查简报.docx'); //导出的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;
}
注意:图片地址需转换成base64
UrlToBase64(url, callback) {
let image = new Image();
//解决跨域问题
image.setAttribute('crossOrigin', 'anonymous');
image.src = url;
image.onload = () => {
var canvas = document.createElement('canvas');
canvas.width = image.width;
canvas.height = image.height;
var context = canvas.getContext('2d');
context.drawImage(image, 0, 0, image.width, image.height);
var quality = 0.8;
var dataURL = canvas.toDataURL('image/png', quality);
callback && callback(dataURL); //回调函数的参数就是base64类型字符串
};
},
最后,有图片的话导出比较久(因为用canvas原宽高转base64,所以导出的图片比较大),如果想优化word导出,应该还是要前后端一起配合。
有错误欢迎指正,最后更新2023.1.11