基于docxtemplater库实现docx文档导出

455 阅读2分钟

纯前端根据数据生成docx文档

基于docxtemplater库实现,通过jszip和file-saver实现打包下载

demo示例下载

gitee地址:docx-create

项目主要使用的依赖以及版本

    "docxtemplater": "^3.55.8",
    "docxtemplater-image-module-free": "^1.1.1",
    "file-saver": "^2.0.5",
    "jszip": "^3.10.1",
    "jszip-utils": "^0.1.0",
    "pizzip": "^3.1.7",
  • 依赖安装需要注意,加载图片时需要使用docxtemplater-image-module-free,不要使用docxtemplater-image-module,这是收费的插件。

主要实现逻辑

  1. 将需要导出的docx模板,根据docxtemplater模板填充要求,vue2工程放到public/目录下

    • docxtemplater官网传送门:docxtemplater

    • docx模板常用配置如图所示:

      • { name } 常量

      • { %photo } 图片

      • { #list } { / } 循环,在循环体中使用常量达到循环效果

pic.png

*   docx模板中,需要导出的图片,需要使用docxtemplater-image-module-free插件

2. 引入需要的依赖


import Docxtemplater from 'docxtemplater';
import JSZip from 'jszip';
import JSZipUtils from 'jszip-utils';
import { saveAs } from 'file-saver';
import PizZip from "pizzip";
import PizZipUtils from "pizzip/utils/index.js";
import ImageModule from "docxtemplater-image-module-free";

  1. 根据docx模板生成docx文档
  • 生成文档主方法
    JSZipUtils.getBinaryContent(this.fileTemplete + '.docx',async  (error, content) => {
        // 抛出异常
        if (error) throw error;
        if (this.exportData.length === 0) {
            console.log("没有文件")
        }
        //单文件
        if (this.exportData.length === 1) {
            const zip = new PizZip(content);
            const doc = new Docxtemplater(zip, {
                //图片加载使用的插件
                modules: [new ImageModule(imageOpts)],
                paragraphLoop: true,
                linebreaks: true,
            });
            //exportData是导出的数据
            //这里只能使用renderAsync异步渲染,因为图片加载是异步的
            await doc.renderAsync(this.exportData[0]);
            const out = doc.getZip().generate({
                type: "blob",
                mimeType:
                    "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
            });
            saveAs(out, this.exportData[0].fileName + '.docx');
        } else {
            const _zip = new JSZip();
            //导出压缩包文件名
            const outDocName = this.zipName
            Promise.all(
                this.exportData.map(async (item, index) => {
                    const zip = new PizZip(content);
                    const doc = new Docxtemplater(zip, {
                        modules: [new ImageModule(imageOpts)],
                        paragraphLoop: true,
                        linebreaks: true,
                    });

                    // 这里只能使用renderAsync异步渲染,因为图片加载是异步的
                    await doc.renderAsync({ ...item });

                    // 生成单个文档的 Blob
                    const out = doc.getZip().generate({
                        type: "blob",
                        mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
                    });

                    // 将生成的文件添加到 zip 中
                    _zip.file(`${index + 1}-${item.fileName}.doc`, out);
                })
            ).then(() => {
                // 所有文档处理完成后,生成 ZIP 文件并下载
                _zip.generateAsync({ type: "blob" }).then((content) => {
                    saveAs(content, `${outDocName}.zip`);
                });
            }).catch((error) => {
                console.error("生成文档失败:", error);
            });
        }
    })
    ```
    - imageOpts配置

    ```
    const imageOpts = {
        //获取图片数据,这里使用了异步获取,也可以直接返回图片数据
        getImage: async function (imageUrl) {
            const response = await fetch(imageUrl);
            const arrayBuffer = await response.arrayBuffer();
            console.log("arrayBuffer", arrayBuffer)
            return Buffer.from(arrayBuffer); // 转为 Buffer
        },
        //获取图片大小,这里只使用了固定比例,也可以异步获取
        getSize: () => {
            const width = 100; // px
            const height = (200 / 16) * 9; // 假设宽高比为 16:9
            return [width, height];
        }
    }
    ```