1. 首页 » 生活技巧

docx怎么转换成word文档(前端开发)

最近开发中遇到需要列表中的表格数据导出word,由于列表表格中的数据是动态表单拖拽产生的,格式就不太固定,想到的方案就是,固定个word模板,然后拿出表格的模板字段进行赋值导出,具体业务实现就不细说,下面说下导出实现。

需要的相关插件

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

jszip: 是为了生成压缩包批量下载,不需要批量处理的可以不用安装

docxtemplater-image-module-free: 如果导出设计到图片的需要安装没有的也可以不用安装

安装

npm i docxtemplater pizzip jszip-utils file-saver jszip docxtemplater-image-module-free -S

处理逻辑

读取并获得模板文件的二进制内容
 JSZipUtils.getBinaryContent('test.docx', (error, content) => {})

2.文件转zip 文件

const zip = new PizZip(content);

3.创建并加载docxtemplater实例对象

 let doc = new docxtemplater().loadZip(zip).compile();

4.加载数据

前端开发——模版导出word下载

5.模板定义

前端开发——模版导出word下载

模板

测试数据

前端开发——模版导出word下载

测试数据

效果展示

前端开发——模版导出word下载

图片关键代码处理

前端开发——模版导出word下载

批量下载处理

前端开发——模版导出word下载

这个地方在打包完下载的时候加了个延迟处理,避免操作不完全

综合封装下

对上面的分散JS做下封装处理,新建exportWord.js

import docxtemplater from "docxtemplater"
import PizZip from "pizzip"
import { saveAs } from "file-saver"
import JSZipUtils from "jszip-utils"
import JSZip from 'jszip'
import ImageModule from "docxtemplater-image-module-free"

export const dataURLToBase64 = (url) => {
  return new Promise((resolve, reject) => {
    // 判断下传入的地址是不是已经是base64
    const base64Regex = /^data:image\/(png|jpg|svg|svg\+xml);base64,/;
    if (base64Regex.test(url)) {
      return url;
    }
    const Img = new Image()
    let dataURL = ''
    Img.setAttribute('crossOrigin', 'Anonymous')
    Img.src = url + '?v=' + Math.random()
    Img.onload = function () {
      // 要先确保图片完整获取到,这是个异步事件
      const canvas = document.createElement('canvas') // 创建canvas元素
      const width = Img.width // 确保canvas的尺寸和图片一样
      const height = Img.height
      canvas.width = width
      canvas.height = height
      canvas.getContext('2d').drawImage(Img, 0, 0, width, height) // 将图片绘制到canvas中
      dataURL = canvas.toDataURL('image/jpeg') // 转换图片为dataURL
      resolve(dataURL)
    }
  })
}
export const exportWord = ({ file = "input.docx", data, filename = "下载文档", fileType = "docx", folder = "下载文档" } = {}) => {
  // 批量下载生成压缩包
  const Zip = new JSZip()
  if (Array.isArray(data)) {
    data.map((item, index) => {
      // 读取并获得模板文件的二进制内容
      JSZipUtils.getBinaryContent(file, (error, content) => {
        // input.docx是模板。我们在导出的时候,会根据此模板来导出对应的数据
        // 抛出异常
        if (error) {
          throw error
        }
        // 图片处理
        let opts = {}
        opts.centered = true;  // 图片居中
        opts.getImage = (tagValue, tagName) => {
          return new Promise((resolve, reject) => {
            JSZipUtils.getBinaryContent(tagValue, (error, content) => {
              if (error) {
                return reject(error);
              }
              return resolve(content);
            });
          });
        }
        opts.getSize = () => {
          return [400, 200]
        }
        let imageModule = new ImageModule(opts);
        // 创建一个JSZip实例,内容为模板的内容
        const zip = new PizZip(content);
        // 创建并加载docxtemplater实例对象
        let doc = new docxtemplater().loadZip(zip).attachModule(imageModule).compile();

        let word = Zip.folder(folder)
        doc.resolveData(item).then(() => {
          doc.render();
          const out = doc.getZip().generate({
            type: "blob",
            mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
          });
          word.file(`${item.filename ? item.filename : filename + index}.${fileType}`, out)
        })
        console.log(word, 'word')
      })
    })
    setTimeout(() => {
      Zip.generateAsync({ type: "blob" })   // zip下载
        .then((content) => {
          saveAs(content, `${folder}.zip`);  // zip下载后的名字
        });
    }, 1000)
  } else {
    // 读取并获得模板文件的二进制内容
    JSZipUtils.getBinaryContent(file, (error, content) => {
      // 抛出异常
      if (error) {
        throw error
      }
      // 图片处理
      let opts = {}
      opts.centered = true;  // 图片居中,在word模板中定义方式为{%image}
      opts.getImage = (tagValue, tagName) => {
        return new Promise((resolve, reject) => {
          JSZipUtils.getBinaryContent(tagValue, (error, content) => {
            if (error) {
              return reject(error);
            }
            return resolve(content);
          });
        });
      }
      opts.getSize = () => {
        return [600, 300]
      }
      let imageModule = new ImageModule(opts);
      const zip = new PizZip(content);
      // 创建并加载docxtemplater实例对象
      let doc = new docxtemplater().loadZip(zip).attachModule(imageModule).compile();
      // 如果包含异步数据,用resolveData,在回调之后再处理,如果都是同步数据,直接用setData就可以
      doc.resolveData(data).then(() => {
        try {
          // 用模板变量的值替换所有模板变量
          doc.render();
          // 生成一个代表docxtemplater对象的zip文件(不是一个真实的文件,而是在内存中的表示)
          const out = doc.getZip().generate({
            type: "blob",
            mimeType:
              "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
          });
          // 将目标文件对象保存为目标类型的文件,并命名
          saveAs(out, `${filename}.${fileType}`);
        } catch (error) {
          // 抛出异常
          const e = {
            message: error.message,
            name: error.name,
            stack: error.stack,
            properties: error.properties
          };
          console.log(JSON.stringify({ error: e }));
          throw error;
        }
      })
    });
  }
}

使用

导入上面定义的JS,使用exportWord方法

import {exportWord} from './exportWord'
const config = {
        file: "test.docx", 
        filename:'下载文档',
        fileType:'docx',
        folder:'下载文档',
        data: {}// 数据
      }
      exportWord(config)

参数说明:

参数

类型

默认值

说明

file

String

模板文件的地址

filename

String

下载文档

文件名称

fileType

String

docx

文件类型

folder

String

下载文档

批量下载压缩包的文件名

data

Array/Object

{}

数据(数组默认批量,对象默认单个下载)

开发的过程中也看到了别人写的,也借鉴参考学到了很多,这地方再进行整合下希望能帮助到也需要相似功能的你们。

声明:本文由"麦兜"发布,不代表"知识分享"立场,转载联系作者并注明出处:https://www.wuxiaoyun.com/life/170909.html