当前位置:首页 » 《我的小黑屋》 » 正文

docxtemplater 实现前端word模板修改(普通文本、图片、表格),并且下载

1 人参与  2024年12月25日 14:01  分类 : 《我的小黑屋》  评论

点击全文阅读


一、问题背景

        项目业务需要,需要实现下载word,并且对word中的内容进行指定输出,包含普通文本、图片、以及表格;

        Documentation | docxtemplater 可以实现对模板word内容的替换; 非常好用,但是存在部分插件使用收费情况,所以选择其它免费的代替,图片使用 docxtemplater-image-module-free,表格使用它自带的循环去实现,缺点就是不能自定义表格,必须要提前在模板中内置好表格使用;

二、相关准备

        我使用的是vite+ts 、使用需要安装指定包;

npm i docxtemplater pizzip docxtemplater-image-module-free file-saver

        准备word模板 - 模板要求

        普通文本 {time}

        图片 {%img}

        表格 {#table}{col1} {col2} {col3}{/table}

        准备好模板后,将模板放入项目的public文件夹内,以便后续使用;

三、过程

        读取文件,传入对应的模板word地址;

import PizZipUtils from "pizzip/utils/index.js";// 读取并获得模板文件的二进制内容// url - '/新建DOCX文档.docx'loadFile(url: string, callback: (error: any, content: any) => void) {  PizZipUtils.getBinaryContent(url, callback);}

        在对应的回调里面去生成pizZip对象, 传入  docxtemplater 对象中,进行处理;并且使用免费的图片图例插件,导入docxtemplater中使用;

// docxtemplater 文件模板修改工具import Docxtemplater from "docxtemplater";// 文件读取工具import PizZip from "pizzip";// 创建一个JSZip实例,内容为模板的内容  setPizZip(error:Error | null, _content) {    // 设置图片资源 免费转换操作    const imageOpts = {      getImage: function(tagValue, tagName) {        return new Promise(function (resolve, reject) {          PizZipUtils.getBinaryContent(tagValue, function (error, content) {            if (error) {              return reject(error);            }            return resolve(content);          });        });      },      getSize: (img, tagValue, tagName) => {        return new Promise(function (resolve, reject) {          const image = new Image();          image.src = tagValue;          image.onload = function () {            resolve([image.width, image.height]);          };          image.onerror = function (e) {            console.log("img, tagValue, tagName : ", img, tagValue, tagName);            alert("An error occured while loading " + tagValue);            reject(e);          };        });      }    }    const zip: PizZip = new PizZip(_content);    // 初始化docxTemplater    this.docContent = new Docxtemplater(zip, {      modules: [        new ImageModule(imageOpts)      ],      paragraphLoop: true,      linebreaks: true    })    return this.setTemplateContent(this.data)  }

最后将模板中需要替换的内容传入

// 设置新模板内容 // 设置模板变量的值/**    _obj = {        time: '123',        img:'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAkEAAADJCAYAAA' // base64格式 或者图片地址        table: [{            col1: 1,            col2: 1,            col3: 1        }]    }*/setTemplateContent(_obj) {  return this.docContent.renderAsync(_obj)}

        rederAsync是返回是一个Promise,我们可以在它的then方法里面去执行操作,进行下载操作;

// 下载文件  downloadFile() {    // 生成一个代表docxtemplater对象的zip文件(不是一个真实的文件,而是在内存中的表示)    const out = this.docContent.getZip().generate({      type: "blob",      mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document"    });    // 将目标文件对象保存为目标类型的文件,并命名    saveAs(out, this.fileName);  }

四、实现效果

五、完整代码

        上面逻辑实现,建议封装工具类,以便后续多文件修改调用;

/* * @Author: autor * @Date: 2024-10-31 09:29:52  * @Last Modified by: autor * @Last Modified time: 2024-10-31 13:39:40 */// docxtemplater 文件模板修改工具import Docxtemplater from "docxtemplater";// 文件读取工具import PizZip from "pizzip";import PizZipUtils from "pizzip/utils/index.js";// docxtemplater - 免费转换图片工具import ImageModule from 'docxtemplater-image-module-free'// 下载工具import {  saveAs} from "file-saver";class ExportWord {  public url: string  public fileName: string  public data: any  public docContent: Docxtemplater  constructor(option) {    this.url = option.url    this.fileName = option.filename    this.data = option.obj  }  // initWord  initWord(_callback) {    this.loadFile(this.url, (error:Error | null, _content) => {      this.setPizZip(error, _content).then(res => {        _callback(this)      }).catch(err => {        ElMessage.error('下载异常,请重试')      })    })  }  // 读取并获得模板文件的二进制内容  loadFile(url: string, callback: (error: any, content: any) => void) {    PizZipUtils.getBinaryContent(url, callback);  }  // 创建一个JSZip实例,内容为模板的内容  setPizZip(error:Error | null, _content) {    // 设置图片资源 免费转换操作    const imageOpts = {      getImage: function(tagValue, tagName) {        return new Promise(function (resolve, reject) {          PizZipUtils.getBinaryContent(tagValue, function (error, content) {            if (error) {              return reject(error);            }            return resolve(content);          });        });      },      getSize: (img, tagValue, tagName) => {        return new Promise(function (resolve, reject) {          const image = new Image();          image.src = tagValue;          image.onload = function () {            resolve([image.width, image.height]);          };          image.onerror = function (e) {            console.log("img, tagValue, tagName : ", img, tagValue, tagName);            alert("An error occured while loading " + tagValue);            reject(e);          };        });      }    }    const zip: PizZip = new PizZip(_content);    // 初始化docxTemplater    this.docContent = new Docxtemplater(zip, {      modules: [        new ImageModule(imageOpts)      ],      paragraphLoop: true,      linebreaks: true    })    return this.setTemplateContent(this.data)  }  // 设置新模板内容   // 设置模板变量的值  setTemplateContent(_obj) {    try {      // 用模板变量的值替换所有模板变量      return this.docContent.renderAsync(_obj);    } catch (error: any) {      // The error thrown here contains additional information when logged with JSON.stringify (it contains a properties object containing all suberrors).      // eslint-disable-next-line no-inner-declarations      function replaceErrors(key: any, value: any) {        if (value instanceof Error) {          return Object.getOwnPropertyNames(value).reduce(function (            error: any,            key: string          ) {            error[key] = value[key as keyof Error];            return error;          }, {});        }        return value;      }      console.log(JSON.stringify({        error: error      }, replaceErrors));      if (error.properties && error.properties.errors instanceof Array) {        const errorMessages = error.properties.errors          .map(function (error: any) {            return error.properties.explanation;          })          .join("\n");        console.log("errorMessages", errorMessages);        // errorMessages is a humanly readable message looking like this : 'The tag beginning with "foobar" is unopened'      }      throw error;    }  }  // 下载文件  downloadFile() {    // 生成一个代表docxtemplater对象的zip文件(不是一个真实的文件,而是在内存中的表示)    const out = this.docContent.getZip().generate({      type: "blob",      mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document"    });    // 将目标文件对象保存为目标类型的文件,并命名    saveAs(out, this.fileName);  }}export default ExportWord;

调用方式:

import ExportWord from '@/utils/exportWord'import { EChartsOption, init, graphic as echartsGraphic, dispose } from 'echarts';const _chartImage = Echart.getDataURL({  backgroundColor: 'rgba(0, 0, 0, 0.7)',  pixelRatio: 0.8})const newFileName = '测试word修改.docx'const _word = new ExportWord({  url: '新建DOCX文档.docx',  filename: newFileName,  obj: {     time: '123',     img: _chartImage,     tableData:  [{       col1: 1,       col2: 1,       col3: 1     }],   }})_word.initWord((_this) => {  _this.downloadFile()})


点击全文阅读


本文链接:http://m.zhangshiyu.com/post/206677.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1