纯前端导出word(含echarts)

解决的是导出含有echarts的页面为word文档,需要考虑echarts图表的大小,采用的是设置角度解析器来预设置图片宽高,也考虑到多图导出问题,下面是我的解决过程

添加所需依赖:
  • npm install docxtemplater
  • npm install pizzip
  • npm install jszip-utils
  • npm install jszip
  • npm install file-saver
  • npm install docxtemplater-image-module
导出word的主要方法

   建立一个word.js,内容如下

import PizZip from 'pizzip'
import Docxtemplater from 'docxtemplater'
import JszipUtils from 'jszip-utils/lib'
import FileSave from 'file-saver'

/**
 * echarts图转为base64
 * 注意事项,echarts图使用canvas绘制,勿使用SVG绘制
 */
export const downloadImgByChart = (myChart) => {
    /** 调用方式
     * let myChart = echarts.getInstanceByDom(document.getElementById('energychart'));
     * downloadImgByChart(myChart)
     */
    var url = myChart.getDataURL({
        pixelRatio: 5,//导出的图片分辨率比率,默认是1
        backgroundColor: '#fff',//图表背景色
        excludeComponents: [ 'toolbox'],//忽略组件的列表
        type: 'png',//图片类型支持png和jpeg
    });
    return url;
}

/**
 * base64转为ArrayBuffer
 */
export const base64DataURLToArrayBuffer = (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;
}

/**
 * 导出word主函数
 */
export const exportWord = (fileDocx, data, outName) => {
    let ImageModule = require('docxtemplater-image-module');
    const expressions = require("angular-expressions");
    //获取模板中的图片值{%image | size:200:100}
    expressions.filters.size = function (input, width, height) {
        return {
            data: input,
            size: [width, height],
        };
    };
    function angularParser(tag) {
        const expr = expressions.compile(tag.replace(/’/g, "'"));
        return {
            get(scope) {
                return expr(scope);
            },
        };
    }
    // 将文件转为二进制
    JszipUtils.getBinaryContent(fileDocx, function(err, res) {
        if (err) { throw err}
        let 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 [500, 500];
        };
        // 将文件转为zip文件
        let pizZip = new PizZip(res)
        // 创建Docxtemplater对象实例并添加zip文件
        let doc = new Docxtemplater()
        doc.loadZip(pizZip)
        doc.setOptions({ parser: angularParser });
        doc.attachModule(new ImageModule(opts));
        // 设置填充内容
        doc.setData(data)
        // 进行内容填充
        try {
            doc.render()
        } catch (error) {
            // 抛出异常
            let e = {
                message: error.message,
                name: error.name,
                stack: error.stack,
                properties: error.properties
            };
            console.log(JSON.stringify({ error: e }));
            throw error;
        }
        // 获取要下载的文件
        let out = doc.getZip().generate({
            type: 'blob',
            mimeType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
        })
        // 进行下载
        FileSave(out, outName)
    })
}

内部的坑

不知道模板文件如何导入或导入错误,JszipUtils.getBinaryContent(fileDocx, function(err, res) {})时,不知道这个fileDocx模板文件放在哪里,然后出现引入路径错误

Error: Can't find end of central directory : is this a zip file?

解决方案:

在使用vue-cli2时,我们需要把模板文件放到static目录下

在使用vue-cli3时,我们需要把模板文件放在public目录下

然后当config中的publicPath是'./'时,直接传入文件名就好,如

JszipUtils.getBinaryContent('template.docx', function(err, res) {})

当config中的publicPath是 ‘/’时,则需要../一层层到相应位置,要特别注意省去public目录,如

JszipUtils.getBinaryContent('../../template.docx', function(err, res) {})

调用导出方法

我的环境是vue-cli3,然后再public目录下建立word文件夹存放模板文件weektmp.docx

Untitled.png
模板样例
Untitled1.png
成品样例
Untitled2.png

你可能感兴趣的:(纯前端导出word(含echarts))