docxtemplater是一个用于处理和生成Word文档的模板引擎

插件准备:npm install --save docxtemplater pizzip jszip-utils jszip file-saver

如果想使用高级语法,可引入以下两个插件, 可解析更多表达式:

npm install --save angular-expressions lodash

1、下载word

tempDocxPath:文件路径(一般放在项目public下)
wordData:数据
fileName:压缩包名字
export const exportWordFormat = (tempDocxPath: string, wordData: object, fileName: string) => {
    let promises: any = [];
    let jsZip = new JSZip();
    let list = Object.values(wordData);
    for (let i = 0; i <= list.length - 1; i++) {
        let filename = (i+1) + '_' + list[i].realname + ".docx";
        const data = list[i];
        const promise = new Promise((resovle) => {
            // 读取并获得模板文件的二进制内容
            JSZipUtils.getBinaryContent(tempDocxPath, async function (error: any, content: any) {
                if (error) {
                    throw error;
                }

                const imageOpts = {
                    getImage: function (tagValue, tagName) {
                        if (tagValue.search(/https:/i) >= 0) {
                            return new Promise(function (resolve, reject) {
                                let image = new Image();
                                image.src = tagValue + "?v=" + Math.random(); // 处理缓存
                                image.crossOrigin = "*"; // 支持跨域图片
                                image.onload = function () {
                                    let base64 = drawBase64Image(image);
                                    const base64Value = base64Parser(base64);
                                    resolve(base64Value);
                                };
                                image.onerror = function () {
                                    reject(new Error("Image failed to load"));
                                };
                            });
                        }
                    },
                    getSize() {
                        return [100, 100];
                    },
                    getProps: function (img, tagValue, tagName) {
                        return {
                            align: "left",
                        };
                    },
                };

                const base64Regex = /^data:image\/(png|jpg|png|svg|svg\+xml);base64,/;
                function base64Parser(dataURL) {
                    if (typeof dataURL !== "string" || !base64Regex.test(dataURL)) {
                        return false;
                    }
                    const stringBase64 = dataURL.replace(base64Regex, "");
                    if (typeof Buffer !== "undefined" && Buffer.from) {
                        return Buffer.from(stringBase64, "base64");
                    }
                    const binaryString = window.atob(stringBase64);
                    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;
                }

                const imageModule = new ImageModule(imageOpts);
                // 创建一个PizZip实例,内容为模板的内容
                const zip = new PizZip(content);
                expressions.filters.lower = function (input: any) {
                    if (!input) return input;
                    return input.toLowerCase();
                };

                function angularParser(tag: any) {
                    tag = tag.replace(/^\.$/, "this").replace(/(’|‘)/g, "'").replace(/(“|”)/g, '"');
                    const expr = expressions.compile(tag);
                    return {
                        get: function (scope: any, context: any) {
                            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]);
                            }
                            obj = assign(obj, { $index: index });
                            return expr(scope, obj);
                        },
                    };
                }
                // 创建并加载docxtemplater实例对象
                const doc = new Docxtemplater()
                    .loadZip(zip)
                    .setOptions({
                        paragraphLoop: true,
                        linebreaks: true,
                        parser: angularParser,
                    })
                    .attachModule(imageModule)
                    .compile();
                let params = {}
                    params = {
                        realname: data.realname || " ", // 姓名
                        sex: data.sex || " ", // 性别
                        option: data.option_config
                    }
                    
                doc.renderAsync(params).then(function () {
                    const out = doc.getZip().generate({
                        type: "blob",
                        mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
                    });
                    if (list.length > 1) {
                        jsZip.file(filename, out, { binary: true });
                        if (i == list.length - 1) {
                            jsZip.generateAsync({ type: "blob" }).then((content) => {
                                saveAs(content, fileName);
                            });
                        }
                    } else {
                        saveAs(out, `${data.realname}.docx`);
                    }
                });
            });
            resovle(true);
        });
        promises.push(promise);
    }
};

2、下载调查表,对勾

首先写好word模板,处理好数据格式

模板中写法:输入大写R,选中之后修改字体为wingding2即可转成对勾框

{#option}{name}{#op} {name}{checked}{/op}{/}
选中{checked}修改字体为wingding2


代码处理:

                data[i].option_config = data[i].option_config.map((item:any) => ({
                    name: item.name,
                    op: [
                        { name: "很好", checked: item.option == 1 ? "☑" : "□" },
                        { name: "一般", checked: item.option == 2 ? "☑" : "□" },
                        { name: "不满意", checked: item.option == 3 ? "☑" : "□" }
                    ]
                }));
数据格式如下:
option_config:[
    {
        name: "学习过程中",
        op:[{name: '很好', checked: '□'},
             {name: '一般', checked: '□'},
             {name: '不满意', checked: '□'}
        ]
    },
]

3、docxtemplater语法

a:'变量渲染'
1、变量渲染:{a}
img:'https:dhfjkfhk'
2、图片渲染:{%img}
let list = [{name: '张三', age: 12}, {name: '李四', age: 23}];
3、循环:{#list}{name}{age}{/}  或者  {#list}{name}{age}{/list}
let list2 = [{name: '张三', sex: 0}, {name: '李四', sex: 1];
4、循环+判断
{#list2}{#sex == 0}男{/sex == 0}{#sex == 1}女{/sex == 1}{/}

更多推荐