Word 模板导出实战 - 前端开发必备技能
前言
在日常开发工作中,Word 文档导出是一个非常常见的需求。无论是生成合同、制作报表,还是导出证书,都离不开 Word 导出功能。本文将详细介绍如何使用 docxtemplater 等工具库,轻松实现 Word 模板导出功能。
应用场景
在实际业务开发中,Word 导出的应用场景非常广泛:
合同文档生成
- 销售合同
- 劳动合同
- 租赁协议等
报告导出
- 财务报表
- 工作总结
- 数据分析报告
- 证书制作
- 获奖证书
- 培训证书
- 资格证明
- 公文处理
- 公文模板
- 通知文件
- 会议纪要
技术方案对比
常见的 Word 导出方案对比:
方案 | 优点 | 缺点 |
---|---|---|
docxtemplater | - 功能强大 - 支持图片 - | - 只支持.docx 格式 高版本付费使用 |
mammoth | - 支持格式转换 - 使用简单 | - 功能相对简单 |
html-docx | - 直接转换 HTML | - 样式支持有限 |
所需依赖
首先需要安装以下依赖包:
shell
npm i --save docxtemplater pizzip jszip-utils file-saver docxtemplater-image-module-free angular-expressions
主要用到的库:
- docxtemplater - 核心模板引擎
- pizzip - ZIP 文件处理
- jszip-utils - ZIP 工具函数
- file-saver - 文件保存
- docxtemplater-image-module-free - 图片处理模块
核心代码实现
完整代码实现
javascript
/**
* 导出word文档(带图片)
*/
import Docxtemplater from "docxtemplater";
import PizZip from "pizzip";
import JSZipUtils from "jszip-utils";
import * as fileSaver from "file-saver";
import * as ImageModule from "docxtemplater-image-module-free";
import expressionParser from "docxtemplater/expressions.js";
/**
* 将base64格式的数据转为ArrayBuffer
* @param {Object} dataURL base64格式的数据
*/
function base64Parser(dataURL) {
const base64Regex = /^data:image\/(png|jpg|jpeg|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 = Buffer.from(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;
}
export const ExportBriefDataDocx = (
tempDocxPath,
data,
fileName,
imgSize = {}
) => {
expressionParser.filters.size = function (input, width, height) {
return {
data: input,
size: [width, height],
};
};
function angularParser(tag) {
tag = tag
.replace(/^\.$/, "this")
.replace(/('|‘)/g, "'")
.replace(/(“|”)/g, '"');
const expr = expressions.compile(tag);
return {
get: function (scope, context) {
let obj = {};
const index = last(context.scopePathItem);
const scopeList = context.scopeList;
const num = context.num;
for (let i = 0, len = num + 1; i < len; i++) {
obj = assign(obj, scopeList[i]);
}
//word模板中使用 $index+1 创建递增序号
obj = assign(obj, { $index: index });
return expr(scope, obj);
},
};
}
JSZipUtils.getBinaryContent(tempDocxPath, (error, content) => {
console.log("content", content);
if (error) {
console.log(error);
}
// expressions.filters.size = function (input, width, height) {
// return {
// data: input,
// size: [width, height],
// };
// };
let imageOptions = {
//图像是否居中
centered: true,
getImage(chartId) {
//将base64的数据转为ArrayBuffer
return base64Parser(chartId);
},
getSize(img, base64, tagName) {
// 获取默认图片尺寸
if (imgSize.hasOwnProperty(tagName)) {
return imgSize[tagName];
} else {
return [200, 200];
}
},
};
// 创建一个JSZip实例,内容为模板的内容
const zip = new PizZip(content);
// 创建并加载 Docxtemplater 实例对象
let doc = new Docxtemplater();
doc.attachModule(new ImageModule(imageOptions));
doc.loadZip(zip);
doc.setOptions({ parser: expressionParser });
doc.setData(data);
try {
doc.render();
} catch (error) {
const e = {
message: error.message,
name: error.name,
stack: error.stack,
properties: error.properties,
};
console.log("err", { error: e });
throw error;
}
// 生成一个代表Docxtemplater对象的zip文件
const out = doc.getZip().generate({
type: "blob",
mimeType:
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
});
fileSaver.saveAs(out, fileName);
});
};
/**
* @description 将图片的url路径转为base64路径
* @param {string} imgUrl - 图片的url路径
* @returns {Promise<string>} - 返回base64路径
*/
export function getBase64Sync(imgUrl) {
return new Promise(function (resolve, reject) {
let image = new Image();
image.src = imgUrl;
image.setAttribute("crossOrigin", "*");
image.onload = function () {
let canvas = document.createElement("canvas");
canvas.width = image.width;
canvas.height = image.height;
let context = canvas.getContext("2d");
context.drawImage(image, 0, 0, image.width, image.height);
let ext = image.src
.substring(image.src.lastIndexOf(".") + 1)
.toLowerCase();
let quality = 0.8;
let dataurl = canvas.toDataURL("image/" + ext, quality);
resolve(dataurl);
};
});
}
/**
* @description 获取图片尺寸
* @param {string} base64 - 图片的base64路径
* @returns {Promise<{width: number, height: number}>} - 返回图片尺寸
*/
export function getImageSize(base64) {
const img = new Image();
img.src = base64;
return new Promise((resolve, reject) => {
img.onload = function () {
resolve({
width: img.width,
height: img.height,
});
};
});
}
使用示例
1. 基础循环示例Loop
2. 表格处理示例Table
支持以下表格类型:
- 一维表格
- 二维表格
- 立式表格
- grid 表格
3. 合并单元格示例
4. 条件显示示例
注意事项
- 该方案仅支持.docx 格式文件
- 模板中不要添加多余空格,可能导致解析失败
- 图片处理需要注意内存占用
- 大文件处理时建议添加进度提示
小结
本文介绍了使用 docxtemplater 实现 Word 模板导出的完整解决方案。通过合理使用模板语法和相关工具库,我们可以轻松实现各类文档的自动化生成。希望本文对你有所帮助!
参考资料
- docxtemplater 官方文档: https://docxtemplater.com/docs/
- docxtemplater 在线示例: https://docxtemplater.com/demo/
示例
- GitHub 项目地址: demo 相关链接
- stackblitz 在线示例