前言需求
- 根据表格字段生成对应的doc模板文件【如合同、录取通知书等】
- 支持批量下载doc,生成zip压缩文件
为什么要前端生成文件?
一般情况下,生成文件是由后端生成二进制文件,前端获取二进制文件进行浏览器下载。
但是,假如有多个用户,同时请求服务器进行资源的处理和下载,服务器承受的压力会相应变大。
所以,把压力分配到各个用户的浏览器上,服务器只返回数据给前端处理。
- 一般情况
graph LR
后端处理Data --> 后端根据文件类型生成对应的二进制 --> 前端通过api获取二进制 --> 实现浏览器下载
- 纯前端情况
graph LR
后端处理Data --> 前端通过api获取Data --> 根据需求把Data转换成对应的文件 --> 实现浏览器下载
npm包
- docxtemplater:doc模板生成库
- pizzip:实现文档解析和压缩
- file-saver:下载库
开发
- 准备一个模板文件
template.docx。 文档内容以{}括起来的为我们的变量名,如{name}。
- 安装必要包。这里我使用
pnpm
pnpm i docxtemplater pizzip file-saver
- 封装单个文件、zip文件的下载主要代码
import Docxtemplater from "docxtemplater";
import PizZip from "pizzip";
import PizZipUtils from "pizzip/utils/index.js";
import { saveAs } from "file-saver";
...
interface User {
name: string
grade: string
grade_code: string
departments: string
year: string
month: string
}
// vite获取本机文件
function getAssetsImages(name: string) {
return new URL(`/src/assets/${name}`, import.meta.url).href;
}
// 通过PizZip获取文件二进制内容
function loadFile(url: string, callback: Function) {
PizZipUtils.getBinaryContent(url, callback);
}
// 批量生成
async function bathCreate() {
if (multipleSelection.value.length === 0) {
return ElMessage('Please choose!')
}
// 输出的zip文件
const bathZip = new PizZip()
for (let index = 0; index < multipleSelection.value.length; index++) {
const item = multipleSelection.value[index];
// 把选中的进行文档创建,并添加到bathZip压缩文件里
await createDoc(bathZip, item)
}
// 转换成blob文件
const content = bathZip.generate({ type: "blob" });
// 浏览器下载
saveAs(content, "example.zip");
}
/**
* @name 封装单个文件下载
* @param bathZip 批量输出的zip文件
* @param item 用户信息
*/
function createDoc(bathZip: any, item: User) {
return new Promise((resolve) => {
loadFile(
getAssetsImages("template.docx"),
(error: Error, content: ArrayBuffer) => {
if (error) {
throw error;
}
// 获取模板内容,通过pizzip进行转换
const zip = new PizZip(content);
const doc = new Docxtemplater(zip, {
paragraphLoop: true, // 一般开启,建议打开该选项,因为它使渲染更容易推理。
linebreaks: true, // 启用换行符
});
// 设置模板数据
doc.setData(item);
try {
// 进行模板替换渲染
doc.render();
} catch (error) {
throw error;
}
// 以base64输出文件
const out = doc.getZip().generate({
type: "base64",
mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
});
// 以name进行文件命名,并把文件添加到zip文件里
bathZip.file(`${item.name}.docx`, out, { base64: true });
resolve(true)
}
);
})
}
- 实现效果