vue 导出word和Excel两种文件,附带多张图片导出(超详细教程)

编程综合网:天梦星科技官网

小编:张贵顺

在此之前先下载依赖:

npm install -S file-saver xlsx
npm install -D script-loader
npm install js-table2excel
-- 安装 docxtemplater
npm install docxtemplater pizzip  --save

-- 安装 jszip-utils
npm install jszip-utils --save 

-- 安装 jszip
npm install jszip --save

-- 安装 FileSaver
npm install file-saver --save

-- 安装 angular-expressions
npm install angular-expressions --save

-- 安装 image-size
npm install image-size --save

接下来上代码:

  1. 导出Word表格,支持多张图片   ,人狠话不多说,直接上代码

     文件名:exportWordImage.js

/**
 * 导出word文档(带图片)
 *
 */
import Docxtemplater from 'docxtemplater'
import PizZip from 'pizzip'
import JSZipUtils from 'jszip-utils'
import { saveAs } from 'file-saver'

/**
 * 将base64格式的数据转为ArrayBuffer
 * @param {Object} dataURL base64格式的数据
 */
function 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 = Buffer.from(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;
}



export const ExportBriefDataDocx = (tempDocxPath, data, fileName, imgSize) => {
  //这里要引入处理图片的插件
  var ImageModule = require('docxtemplater-image-module-free');
  var expressions = require('angular-expressions')
  var assign = require('lodash/assign')
  var last = require("lodash/last")
  expressions.filters.lower = function (input) {
    if (!input) return input
    return input.toLowerCase()
  }
  function angularParser(tag) {
    tag = tag
      .replace(/^\.$/, 'this')
      .replace(/(’|‘)/g, "'")
      .replace(/(“|”)/g, '"')
    const expr = expressions.compile(tag)
    return {
      get: function (scope, context) {
        let obj = {}
        const index = last(context.scopePathItem)
        const scopeList = context.scopeList
        const num = context.num
        for (let i = 0, len = num + 1; i < len; i++) {
          obj = assign(obj, scopeList[i])
        }
        //word模板中使用 $index+1 创建递增序号
        obj = assign(obj, { $index: index })
        return expr(scope, obj)
      }
    }
  }
  JSZipUtils.getBinaryContent(tempDocxPath, (error, content) => {
    if (error) {
      console.log(error)
    }
    expressions.filters.size = function (input, width, height) {
      return {
        data: input,
        size: [width, height],
      };
    };

    let opts = {}

    opts = {
      //图像是否居中
      centered: false
    };
    opts.getImage = (chartId) => {
      //将base64的数据转为ArrayBuffer
      return base64DataURLToArrayBuffer(chartId);
    }
    opts.getSize = function (img, tagValue, tagName) {
      //自定义指定图像大小
      if (imgSize.hasOwnProperty(tagName)) {
        return imgSize[tagName];
      } else {
        return [100, 100];
      }
    }



    // 创建一个JSZip实例,内容为模板的内容
    const zip = new PizZip(content)
    // 创建并加载 Docxtemplater 实例对象

    // 设置模板变量的值
    let doc = new Docxtemplater();
    doc.attachModule(new ImageModule(opts));
    doc.loadZip(zip);
    doc.setOptions({parser:angularParser});
    doc.setData(data)
    try {
      // 呈现文档,会将内部所有变量替换成值,
      doc.render()
    } catch (error) {
      const e = {
        message: error.message,
        name: error.name,
        stack: error.stack,
        properties: error.properties
      }
      console.log('err',{ error: e })
      // 当使用json记录时,此处抛出错误信息
      throw error
    }
    // 生成一个代表Docxtemplater对象的zip文件(不是一个真实的文件,而是在内存中的表示)
    const out = doc.getZip().generate({
      type: 'blob',
      mimeType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
    })
    // 将目标文件对象保存为目标类型的文件,并命名
    saveAs(out, fileName)
  })
}

/**
 * 将图片的url路径转为base64路径
 * 可以用await等待Promise的异步返回
 * @param {Object} imgUrl 图片路径
 */
export function getBase64Sync(imgUrl) {
  return new Promise(function (resolve, reject) {
    // 一定要设置为let,不然图片不显示
    let image = new Image();
    //图片地址
    image.src = imgUrl;
    // 解决跨域问题
    image.setAttribute("crossOrigin", '*');  // 支持跨域图片
    // image.onload为异步加载
    image.onload = function () {
      let canvas = document.createElement("canvas");
      canvas.width = image.width;
      canvas.height = image.height;
      let context = canvas.getContext("2d");
      context.drawImage(image, 0, 0, image.width, image.height);
      //图片后缀名
      let ext = image.src.substring(image.src.lastIndexOf(".") + 1).toLowerCase();
      //图片质量
      let quality = 0.8;
      //转成base64
      let dataurl = canvas.toDataURL("image/" + ext, quality);
      //返回
      resolve(dataurl);
    };
  })
}

调用函数:

    async expotWord(){

     let data:{
        isTable:[
             {
              id:  1,         
              created_at: "2023-05-19",  
              organ_name:  "测试", 
              title: "测试",        
              url: "测试",          
              region_text:  "测试", 
              involved:   "测试",   
              dissemination:"测试", 
              standpoint:  "测试",  
              risk_content: "测试", 
              eidt_role:  "测试",   
              files_json:  [
                          {imgUrl:'http://172.16.72.27:32114/group1/hzyn/ynwx/feedback/20230516/1684207872385.jpeg'},
                          {imgUrl:'http://172.16.72.27:32114/group1/hzyn/ynwx/feedback/20230516/1684207872385.jpeg'},       
                         ] 
             }
         ]
       };


      for (const item of data.isTable) {
        for (let i in item.files_json) {
          item.files_json[i].imgUrl = await getBase64Sync(item.files_json[i].imgUrl)
        }
      }
      
      
      if (wordData.isTable.length>=1){
        let imgSize = {
          imgurl:[200, 200],//控制导出的word图片大小
        };
        ExportBriefDataDocx(`${"/yqypexportdata"}.docx`, data, "信息测试.docx", imgSize);
      }else {
        this.$message.warning("导出数据不能为空!");
      }

    },

表格模版:文件名: yqypexportdata.docx   位置放public 目录下

 预期效果:

2.导出Excel表格,同样支持多张图片

封装的js: 

/* eslint-disable */
let idTmr;
const getExplorer = () => {
  let explorer = window.navigator.userAgent;
  //ie
  if (explorer.indexOf("MSIE") >= 0) {
    return 'ie';
  }
  //firefox

  else if (explorer.indexOf("Firefox") >= 0) {
    return 'Firefox';
  }
  //Chrome
  else if (explorer.indexOf("Chrome") >= 0) {
    return 'Chrome';
  }
  //Opera
  else if (explorer.indexOf("Opera") >= 0) {
    return 'Opera';
  }
  //Safari
  else if (explorer.indexOf("Safari") >= 0) {
    return 'Safari';
  }
}

const exportToExcel = (data,name) => {

  // 判断是否为IE
  if (getExplorer() == 'ie') {
    tableToIE(data, name)
  } else {
    tableToNotIE(data,name)
  }
}

const Cleanup = () => {
  window.clearInterval(idTmr);
}

const tableToIE = (data, name) => {
  let curTbl = data;
  let oXL = new ActiveXObject("Excel.Application");

  //创建AX对象excel
  let oWB = oXL.Workbooks.Add();
  //获取workbook对象
  let xlsheet = oWB.Worksheets(1);
  //激活当前sheet
  let sel = document.body.createTextRange();
  sel.moveToElementText(curTbl);
  //把表格中的内容移到TextRange中
  sel.select;
  //全选TextRange中内容
  sel.execCommand("Copy");
  //复制TextRange中内容
  xlsheet.Paste();
  //粘贴到活动的EXCEL中

  oXL.Visible = true;
  //设置excel可见属性

  try {
    let fname = oXL.Application.GetSaveAsFilename("Excel.xls", "Excel Spreadsheets (*.xls), *.xls");
  } catch (e) {
    print("Nested catch caught " + e);
  } finally {
    oWB.SaveAs(fname);

    oWB.Close(savechanges = false);
    //xls.visible = false;
    oXL.Quit();
    oXL = null;
    // 结束excel进程,退出完成
    window.setInterval("Cleanup();", 1);
    idTmr = window.setInterval("Cleanup();", 1);
  }
}

const tableToNotIE = (function() {
  // 编码要用utf-8不然默认gbk会出现中文乱码
  let uri = 'data:application/vnd.ms-excel;base64,',
    template = '<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40"><head><meta charset="UTF-8"><!--[if gte mso 9]><xml><x:ExcelWorkbook><x:ExcelWorksheets><x:ExcelWorksheet><x:Name>{worksheet}</x:Name><x:WorksheetOptions><x:DisplayGridlines/></x:WorksheetOptions></x:ExcelWorksheet></x:ExcelWorksheets></x:ExcelWorkbook></xml><![endif]--></head><body><table>{table}</table></body></html>',
    base64 = function(s) {
      return window.btoa(unescape(encodeURIComponent(s)));
    },
    format = (s, c) => {
      return s.replace(/{(\w+)}/g,
        (m, p) => {
          return c[p];
        })
    }
  return (table, name) => {
    let ctx = {
      worksheet: name,
      table
    }
    //创建下载
    let link = document.createElement('a');
    link.setAttribute('href', uri + base64(format(template, ctx)));
    link.setAttribute('download', name);
    // window.location.href = uri + base64(format(template, ctx))
    link.click();
  }
})()

// 导出函数
const export2Excel = (theadData, tbodyData, dataname) => {
  let re = /https?:\\.(png|gif|jpg|jpeg|bmp)/ig // 字符串中包含http,则默认为图片地址(正则)
  let th_len = theadData.length // 表头的长度
  let tb_len = tbodyData.length // 记录条数
  let width = 40 // 设置图片大小
  let height = 60
  // 添加表头信息
  let thead = '<thead><tr>'
  for (let i = 0; i < th_len; i++) {
    thead += '<th>' + theadData[i] + '</th>'
  }
  thead += '</tr></thead>'

  // 添加每一行数据
  let tbody = '<tbody>'
  for (let i = 0; i < tb_len; i++) {
    tbody += '<tr>'
    let row = tbodyData[i] // 获取每一行数据
    for (let key in row) {
      if (re.test(row[key])) { // 如果为图片,则需要加div包住图片
        let listDiv=''
        for (const keyElement of row[key]) {
          listDiv+= '<div>'+'<img src=\'' + keyElement + '\' ' + ' ' + 'width=' + '\"' + width + '\"' + ' ' + 'height=' + '\"' + height + '\"' + '/>'+'</div>'
        }
        tbody += '<td style="width:auto; height:auto; text-align: center; vertical-align: middle">' + listDiv + '</td>'
      } else {
        tbody += '<td style="text-align:center">' + row[key] + '</td>'
      }
    }
    tbody += '</tr>'
  }
  tbody += '</tbody>'

  let table = thead + tbody

  // 导出表格
  exportToExcel(table, dataname)
}
export {
  export2Excel
}




调用:

 expotExcel(e){
      let tbody =[
            {
         id:'',//序号
        created_at:null,//创建时间
        organ_name:null,//上报单位
        title:null,//标题
        url:null,//链接
        region_text:null,//事件属地
        involved:null,//涉事单位
        dissemination:null,//传播情况
        standpoint:null,//网民观点
        risk_content:null,//风险研判
        eidt_role:null,
        files_json:['http://172.16.72.27:32114/group1/hzyn/ynwx/feedback/20230516/1684207872385.jpeg','http://172.16.72.27:32114/group1/hzyn/ynwx/feedback/20230516/1684207872385.jpeg'],//附件
            }
       
         ]
      let tHeader =['序号','创建时间','上报单位','标题','链接','事件属地','涉事单位','传播情况','网民观点','风险研判','选用人','附件']
      let dataTime=this.$moment().format('YYYY-MM-DD HH');
      if (tbody.length>=1){
        export2Excel(tHeader, tbody, '舆情信息汇总'+'('+dataTime+')')
      }else {
        this.$message.warning("导出数据不能为空!");
      }

    },

预期效果:

收到over over!

  • 4
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值