前端导出word文档-图文(vue+echarts)

1,856 阅读2分钟

通过docxtemplater导出word图文

前期准备

安装相关依赖包

    npm install docxtemplater pizzip --save
    npm install jszip-utils --save
    npm install file-saver --save
    npm install docxtemplater-image-module-free --save // **注意**docxtemplater-image-module在这里是不能用的
    npm install echarts --save

引入依赖包

import Docxtemplater from 'docxtemplater'
import JSZipUtils from 'jszip-utils'
import JSZip from 'pizzip'
import { saveAs } from 'file-saver'
import ImageModule from 'docxtemplater-image-module-free'
import * as echarts from 'echarts'

注:引用docxtemplater-image-module-free报错时,可尝试require引入

const ImageModule = require('docxtemplater-image-module-free')

注:导出word文档报错,如下,一般是word模板路径问题,word模板一般放在pubilc根目录,或static根目录

image.png

1、表格 word模板 image.png image.png

    JSZipUtils.getBinaryContent('/word.docx', function (error, content) {
      // 抛出异常
      if (error) {
        throw error
      }
      // 创建一个JSZip实例,内容为模板的内容
      const zip = new JSZip(content)
      // 创建并加载docxtemplater实例对象
      const doc = new Docxtemplater().loadZip(zip)

      // 设置模板变量的值
      doc.setData({
          table: [{
              name: '测试1',
              num: '5',
              rate: '33.33',
          },{
              name: '测试2',
              num: '10',
              rate: '66.66',
          }]
      })
      try {
        // 用模板变量的值替换所有模板变量
        doc.render()
      } catch (error) {
        // 抛出异常
        // const e = {
        //   message: error.message,
        //   name: error.name,
        //   stack: error.stack,
        //   properties: error.properties,
        // }
        console.error('导出报表失败')
        throw error
      }

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

2、echarts图片生成

在模板中使用{%%image}

   // 转换成buffer
  const base64DataURLToArrayBuffer = function (dataURL) {
    const base64Regex = /^data:image\/(png|jpg|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;
  }

  const div = document.createElement('div');
  div.setAttribute('style', 'width: 560px;height:280px;')
    
  const myChart = echarts.init(div)  
  myChart.setOption({
    title: {
      text: '示例'
    },
    tooltip: {},
    legend: {
      data: ['销量']
    },
    xAxis: {
      data: ["衬衫", "羊毛衫", "雪纺衫", "裤子", "高跟鞋", "袜子"]
    },
    yAxis: {},
    series: [{
      name: '销量',
      type: 'bar',
      data: [5, 20, 36, 10, 10, 20]
    }]
  })
    
  setTimeout(() => { // 加setTimeout是为了让echarts渲染完成后生成图片
    JSZipUtils.getBinaryContent('/word.docx', function (error, content) {
      // 抛出异常
      if (error) {
        throw error
      }
      const opts = {
        centered: false,
        fileType: 'docx'
      }
      opts.getImage = function (tagValue) {
        if (tagValue.size && tagValue.data) {
          return base64DataURLToArrayBuffer(tagValue.data);
        }
        return base64DataURLToArrayBuffer(tagValue);
      };
      opts.getSize = function (_, tagValue) {
        if (tagValue.size && tagValue.data) {
          return tagValue.size;
        }
        return [560, 280];
      };
      // 创建一个JSZip实例,内容为模板的内容
      const zip = new JSZip(content)
      // 创建并加载docxtemplater实例对象
      const doc = new Docxtemplater().loadZip(zip)

      doc.setOptions({
        nullGetter: function () { //设置空值 undefined 为''
          return '';
        },
      });
      // 设置图片模块
      doc.attachModule(new ImageModule(opts));

      // 设置模板变量的值
      doc.setData({
        image: myChart.getDataURL({
            pixelRatio: 5, //导出的图片分辨率比率,默认是1
            backgroundColor: '#fff', //图表背景色
            excludeComponents: ['toolbox'], //忽略组件的列表
            type: 'png', //图片类型支持png和jpeg
        })
      })
      try {
        // 用模板变量的值替换所有模板变量
        doc.render()
      } catch (error) {
        // 抛出异常
        // const e = {
        //   message: error.message,
        //   name: error.name,
        //   stack: error.stack,
        //   properties: error.properties,
        // }
        console.error('导出报表失败')
        throw error
      }
      // 生成一个代表docxtemplater对象的zip文件(不是一个真实的文件,而是在内存中的表示)
      const out = doc.getZip().generate({
        type: 'blob',
        mimeType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
      })
      // 将目标文件对象保存为目标类型的文件,并命名
      saveAs(out, `test.docx`)
    })
  }, 1000);

没加 setTimeout

image.png

setTimeout

image.png

word模板常用

{#list}{/list} // 循环
{#isName}{/isName}  // 判断true/false
{name} // 对应字段渲染,例:{name: '测试名称'}
{%%image} // 图片类型