一、问题背景
项目业务需要,需要实现下载word,并且对word中的内容进行指定输出,包含普通文本、图片、以及表格;
Documentation | docxtemplater 可以实现对模板word内容的替换; 非常好用,但是存在部分插件使用收费情况,所以选择其它免费的代替,图片使用 docxtemplater-image-module-free,表格使用它自带的循环去实现,缺点就是不能自定义表格,必须要提前在模板中内置好表格使用;
二、相关准备
我使用的是vite+ts 、使用需要安装指定包;
npm i docxtemplater pizzip docxtemplater-image-module-free file-saver
准备word模板 - 模板要求
普通文本 {time}
图片 {%img}
表格 {#table}{col1} {col2} {col3}{/table}
准备好模板后,将模板放入项目的public文件夹内,以便后续使用;
三、过程
读取文件,传入对应的模板word地址;
import PizZipUtils from "pizzip/utils/index.js";
// 读取并获得模板文件的二进制内容
// url - '/新建DOCX文档.docx'
loadFile(url: string, callback: (error: any, content: any) => void) {
PizZipUtils.getBinaryContent(url, callback);
}
在对应的回调里面去生成pizZip对象, 传入 docxtemplater 对象中,进行处理;并且使用免费的图片图例插件,导入docxtemplater中使用;
// docxtemplater 文件模板修改工具
import Docxtemplater from "docxtemplater";
// 文件读取工具
import PizZip from "pizzip";
// 创建一个JSZip实例,内容为模板的内容
setPizZip(error:Error | null, _content) {
// 设置图片资源 免费转换操作
const imageOpts = {
getImage: function(tagValue, tagName) {
return new Promise(function (resolve, reject) {
PizZipUtils.getBinaryContent(tagValue, function (error, content) {
if (error) {
return reject(error);
}
return resolve(content);
});
});
},
getSize: (img, tagValue, tagName) => {
return new Promise(function (resolve, reject) {
const image = new Image();
image.src = tagValue;
image.onload = function () {
resolve([image.width, image.height]);
};
image.onerror = function (e) {
console.log("img, tagValue, tagName : ", img, tagValue, tagName);
alert("An error occured while loading " + tagValue);
reject(e);
};
});
}
}
const zip: PizZip = new PizZip(_content);
// 初始化docxTemplater
this.docContent = new Docxtemplater(zip, {
modules: [
new ImageModule(imageOpts)
],
paragraphLoop: true,
linebreaks: true
})
return this.setTemplateContent(this.data)
}
最后将模板中需要替换的内容传入
// 设置新模板内容
// 设置模板变量的值
/**
_obj = {
time: '123',
img:'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAkEAAADJCAYAAA' // base64格式 或者图片地址
table: [{
col1: 1,
col2: 1,
col3: 1
}]
}
*/
setTemplateContent(_obj) {
return this.docContent.renderAsync(_obj)
}
rederAsync是返回是一个Promise,我们可以在它的then方法里面去执行操作,进行下载操作;
// 下载文件
downloadFile() {
// 生成一个代表docxtemplater对象的zip文件(不是一个真实的文件,而是在内存中的表示)
const out = this.docContent.getZip().generate({
type: "blob",
mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
});
// 将目标文件对象保存为目标类型的文件,并命名
saveAs(out, this.fileName);
}
四、实现效果
五、完整代码
上面逻辑实现,建议封装工具类,以便后续多文件修改调用;
/*
* @Author: autor
* @Date: 2024-10-31 09:29:52
* @Last Modified by: autor
* @Last Modified time: 2024-10-31 13:39:40
*/
// docxtemplater 文件模板修改工具
import Docxtemplater from "docxtemplater";
// 文件读取工具
import PizZip from "pizzip";
import PizZipUtils from "pizzip/utils/index.js";
// docxtemplater - 免费转换图片工具
import ImageModule from 'docxtemplater-image-module-free'
// 下载工具
import {
saveAs
} from "file-saver";
class ExportWord {
public url: string
public fileName: string
public data: any
public docContent: Docxtemplater
constructor(option) {
this.url = option.url
this.fileName = option.filename
this.data = option.obj
}
// initWord
initWord(_callback) {
this.loadFile(this.url, (error:Error | null, _content) => {
this.setPizZip(error, _content).then(res => {
_callback(this)
}).catch(err => {
ElMessage.error('下载异常,请重试')
})
})
}
// 读取并获得模板文件的二进制内容
loadFile(url: string, callback: (error: any, content: any) => void) {
PizZipUtils.getBinaryContent(url, callback);
}
// 创建一个JSZip实例,内容为模板的内容
setPizZip(error:Error | null, _content) {
// 设置图片资源 免费转换操作
const imageOpts = {
getImage: function(tagValue, tagName) {
return new Promise(function (resolve, reject) {
PizZipUtils.getBinaryContent(tagValue, function (error, content) {
if (error) {
return reject(error);
}
return resolve(content);
});
});
},
getSize: (img, tagValue, tagName) => {
return new Promise(function (resolve, reject) {
const image = new Image();
image.src = tagValue;
image.onload = function () {
resolve([image.width, image.height]);
};
image.onerror = function (e) {
console.log("img, tagValue, tagName : ", img, tagValue, tagName);
alert("An error occured while loading " + tagValue);
reject(e);
};
});
}
}
const zip: PizZip = new PizZip(_content);
// 初始化docxTemplater
this.docContent = new Docxtemplater(zip, {
modules: [
new ImageModule(imageOpts)
],
paragraphLoop: true,
linebreaks: true
})
return this.setTemplateContent(this.data)
}
// 设置新模板内容
// 设置模板变量的值
setTemplateContent(_obj) {
try {
// 用模板变量的值替换所有模板变量
return this.docContent.renderAsync(_obj);
} catch (error: any) {
// The error thrown here contains additional information when logged with JSON.stringify (it contains a properties object containing all suberrors).
// eslint-disable-next-line no-inner-declarations
function replaceErrors(key: any, value: any) {
if (value instanceof Error) {
return Object.getOwnPropertyNames(value).reduce(function (
error: any,
key: string
) {
error[key] = value[key as keyof Error];
return error;
}, {});
}
return value;
}
console.log(JSON.stringify({
error: error
}, replaceErrors));
if (error.properties && error.properties.errors instanceof Array) {
const errorMessages = error.properties.errors
.map(function (error: any) {
return error.properties.explanation;
})
.join("\n");
console.log("errorMessages", errorMessages);
// errorMessages is a humanly readable message looking like this : 'The tag beginning with "foobar" is unopened'
}
throw error;
}
}
// 下载文件
downloadFile() {
// 生成一个代表docxtemplater对象的zip文件(不是一个真实的文件,而是在内存中的表示)
const out = this.docContent.getZip().generate({
type: "blob",
mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
});
// 将目标文件对象保存为目标类型的文件,并命名
saveAs(out, this.fileName);
}
}
export default ExportWord;
调用方式:
import ExportWord from '@/utils/exportWord'
import { EChartsOption, init, graphic as echartsGraphic, dispose } from 'echarts';
const _chartImage = Echart.getDataURL({
backgroundColor: 'rgba(0, 0, 0, 0.7)',
pixelRatio: 0.8
})
const newFileName = '测试word修改.docx'
const _word = new ExportWord({
url: '新建DOCX文档.docx',
filename: newFileName,
obj: {
time: '123',
img: _chartImage,
tableData: [{
col1: 1,
col2: 1,
col3: 1
}],
}
})
_word.initWord((_this) => {
_this.downloadFile()
})
本文转载自: https://blog.csdn.net/m0_51600979/article/details/143393283
版权归原作者 出入编程的小崽子 所有, 如有侵权,请联系我们删除。
版权归原作者 出入编程的小崽子 所有, 如有侵权,请联系我们删除。