前言

Docxtemplater是一个用于生成和操作Word文档的JavaScript库,它允许开发者在前端动态生成和编辑Word文档,用于动态生成报表等功能。

使用方法

  1. 安装依赖‌:首先,你需要安装Docxtemplater及其相关依赖。可以通过npm安装这些库:

    pnpm install docxtemplater pizzip jszip-utils file-saver docxtemplater-image-module-free


  2. 引入依赖‌:在项目中引入必要的模块:

    import Docxtemplater from 'docxtemplater';
    import PizZip from 'pizzip';
    import { saveAs } from 'file-saver';


  3. 创建模板文档‌:在public文件下创建.docx模板文档,变量用大括号包裹。{#变量}表示循环 {%变量}可以放置图片 1742807546816.png

  4. 模板数据匹配‌:在页面中创建对象进行字段对应

<template>
  <div>
    <!-- 下载和打印按钮 -->
    <button @click="downloadDocument">
      Download Document
    </button>
    <button v-if="outputDoc" @click="printDocument">Print Document</button>

    <!-- 错误提示 -->
    <div v-if="errorMessage" style="color: red">
      {{ errorMessage }}
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted } from "vue";
import Docxtemplater from "docxtemplater";
import PizZip from "pizzip";
import { saveAs } from "file-saver";
import axios from "axios";
const ImageModule = require("docxtemplater-image-module-free");//处理图片
const errorMessage = ref(""); // 存储错误信息
const outputDoc = ref(null); // 存储生成的文档
const userData = {
  name: "John Doe",
  email: "john.doe@example.com",
  age: 30,
  option: [
    {
      id: 1,
      gender: 1,
      address: "qqq",
    },
    {
      id: 2,
      gender: 2,
      address: "www",
    },
    {
      id: 3,
      gender: 3,
      address: "eee",
    },
  ],
  people: [
    {
      position: "CEO",
      signatureUrl:
        "http://xxxxxxxxxxx",
    },
    {
      position: "CTO",
      signatureUrl:
        "http://xxxxxxxxxx",
    },
  ],
};

// 加载本地模板文件
async function loadTemplate(filePath) {
  const response = await fetch(filePath);
  const arrayBuffer = await response.arrayBuffer();
  return new Uint8Array(arrayBuffer);
}


// 下载网络图片并转换为 Base64
async function downloadImageToBase64(url) {
  const response = await axios.get(url, { responseType: "arraybuffer" });
  const base64 = btoa(
    new Uint8Array(response.data).reduce(
      (data, byte) => data + String.fromCharCode(byte),
      ""
    )
  );
  return `data:${response.headers["content-type"]};base64,${base64}`;
}
//图片需要转成ArrayBuffer格式
const base64DataURLToArrayBuffer = (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 = new Buffer(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;
};



// 渲染并生成 .docx 文件
async function generateDocx() {
  // 下载图片并更新数据
  for (let employee of userData.people) {
    employee.signature = await downloadImageToBase64(employee.signatureUrl);
  }

  let opts = {};
  opts = {
    // 图像是否居中
    centered: false,
  };

  opts.getImage = (chartId) => {
    // console.log(chartId);//base64数据
    // 将base64的数据转为ArrayBuffer
    return base64DataURLToArrayBuffer(chartId);
  };

  opts.getSize = function (img, tagValue, tagName) {
    // console.log(img);//ArrayBuffer数据
    // console.log(tagValue); //base64数据
    // console.log(tagName);//wordData对象的图像属性名
    // 自定义指定图像大小或直接返回固定尺寸
    return [100, 60];
  };

  // 加载模板文件
  const templateContent = await loadTemplate("/template.docx"); // 假设模板文件在 public 目录
  const zip = new PizZip(templateContent);

  // 初始化 docxtemplater
  const doc = new Docxtemplater();
  doc.attachModule(new ImageModule(opts));
  doc.loadZip(zip);
  doc.setData(userData);

  try {
    doc.render();
    errorMessage.value = ""; // 清空错误信息
  } catch (error) {
    console.error("渲染错误:", error);
    errorMessage.value = "Error rendering template. Please check the template and data.";
    return;
  }

  // 生成 .docx 文件
  const generatedDoc = doc.getZip().generate({ type: "blob" });
  outputDoc.value = generatedDoc;
  // 触发文件下载
  saveAs(generatedDoc, "output.docx");
}


// 下载文档
const downloadDocument = () => {
  // 调用函数
  generateDocx();
};
// 打印文档 
const printDocument = () => { 
    const url = URL.createObjectURL(outputDoc.value); 
    const printWindow = window.open(url); 
    printWindow.onload = () => { printWindow.print(); }; 
};

</script>


输出文档