前端生成 word
docxtemplater 介绍
docxtemplater 使用 JSON 数据格式作为输入,可以处理docx 和 ppt模板。不像一些其它的工具,比如 docx.js 等,需要自己编写代码来生成文件,docxtemplater 只需要用户通过标签的形式编写模板,就可以生成文件。
项目依赖
项目所需依赖:docxtemplater,jszip,jszip-utils,pizzip,file-saver。
- docxtemplater:这个插件可以通过预先写好的word,excel等文件模板生成对应带数据的文件
- pizzip:这个插件用来创建,读取或编辑.zip的文件(同步的,还有一个插件是jszip,异步的)
- jszip-utils:与jszip/pizzip一起使用,jszip-utils 提供一个getBinaryContent(path, data)接口,path即是文件的路径,支持AJAX get请求,data为读取的文件内容。
- file-saver:适合在客户端生成文件的工具,它提供的接口saveAs(blob, "1.docx")将会使用到,方便我们保存文件。
npm install docxtemplater pizzip --save // 处理docx模板
npm install jszip-utils --save
npm install jszip --save
npm install file-saver --save // 处理输出文件
docxtemplater 入门
渲染字符串
语法:
{变量名}
在 word 文档上把需要替换的值换成 {变量名} 的格式
循环遍历
语法:
{#变量名}{/变量名}
遍历表格
当然如果你的数组只是存了基本数据类型情况下,要这样写法才能渲染出来
{#变量名}{$index}{.}{/变量名}
当然有时候你希望控制数组为空的情况下渲染其它的,那么 docxtemplater 提供了 ^ 来判断
{#变量名}{.}{/变量名}
{^变量名} 数据为空 {/变量名}
插入 docxXml 格式
有时候会有一些比较复杂的需求,例如下面的性别要用不同的颜色显示
这时候我们可以使用 docxXml 语法来渲染。
语法:
{@变量名}
相比于渲染字符串,渲染 docxXml 要在前面加多一个 @ 符号,并且变量的值要为 docxXml 语法,如下面所示:
<w:p>
<w:pPr>
<w:pStyle w:val="11"/>
<w:rPr>
<w:rFonts w:hint="eastAsia" w:eastAsia="微软雅黑"/>
<w:color w:val="${color}"/>
<w:szCs w:val="20"/>
<w:lang w:eastAsia="zh-CN"/>
<w:vAlign w:val="center"/>
</w:rPr>
</w:pPr>
<w:r>
<w:rPr>
<w:rFonts w:hint="eastAsia"/>
<!-- 设置字体颜色 -->
<w:color w:val="${color}"/>
<w:szCs w:val="20"/>
<w:lang w:val="en-US" w:eastAsia="zh-CN"/>
</w:rPr>
<w:t>男</w:t>
</w:r>
</w:p>
if 条件语法
语法:{#变量名}{/}
docxtemplater 默认只支持 boolean 值的判断
如果想支持更高级的判断方式的话,必须得添加额外得包
npm install --save angular-expressions
docxtemplater 配置
const expressionParser = require("docxtemplater/expressions.js")
new Docxtemplater(zip, { parser: expressionParser })
这样你就能支持更高级的判断方式了
{#users.length>1}{/}
{#users[0].name == "John"}{/}
当然,这个包不仅扩展了高级的判断方式,更有其它额外的功能,详情情况官网介绍expressions
指定 DOM
在某些情况下, docxtemplater 并不能很好识别我们想要操作的 DOM,例如: 在单列的表格的单元格下,我们希望能控制整行的显示和隐藏
想象中的结果是这样
但事实却是这样
这是因为 docxtemplater 在单列情况下,默认是操作里面内容的 DOM,而不是整行的 DOM。
所在在这样的情况下,就需要我们指定告诉 docxtemplater ,我想你操作的是行 Dom :
{-w:tr table1s.length == 0}未发现{/}
如果是循环也可以这样用
{-w:tr table1s.length == 0}{.}{/table1s}
导出 word 完整代码实现
将demoUrl传入给JSZipUtils.getBinaryContent方法读取模板文件的二进制内容,之后创建一个PizZip实例,内容为模板的内容,再创建并加载docxtemplater实例对象。
使用doc.setData方法设置模板变量的值,对象的键需要和模板上的变量名一致,值就是你要放在模板上的值。
import JSZipUtils from "jszip-utils";
import docxtemplater from "docxtemplater";
import { saveAs } from "file-saver";
import PizZip from "pizzip";
/**
* @param {*} demoUrl 模板路径
* @param {*} docxData 渲染的数据
* @param {*} fileName 生成的文件名
* @returns
*/
export const exportWordDocx = (demoUrl, docxData, fileName) => {
// 读取并获得模板文件的二进制内容
JSZipUtils.getBinaryContent(
demoUrl,
function (error, content) {
// 抛出异常
if (error) {
throw error;
}
// 创建一个PizZip实例,内容为模板的内容
let zip = new PizZip(content);
// 创建并加载docxtemplater实例对象
let doc = new docxtemplater().loadZip(zip);
// 去除未定义值所显示的undefined
doc.setOptions({
nullGetter: function () {
return "";
}
}); // 设置角度解析器
// 设置模板变量的值,对象的键需要和模板上的变量名一致,值就是你要放在模板上的值
doc.setData({
...docxData,
});
try {
// 用模板变量的值替换所有模板变量
doc.render();
} catch (error) {
// 抛出异常
let e = {
message: error.message,
name: error.name,
stack: error.stack,
properties: error.properties,
};
console.log(JSON.stringify({ error: e }));
throw error;
}
// 生成一个代表docxtemplater对象的zip文件(不是一个真实的文件,而是在内存中的表示)
let out = doc.getZip().generate({
type: "blob",
mimeType:
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
});
// 将目标文件对象保存为目标类型的文件,并命名
saveAs(out, fileName);
}
);
}