vue xlsx new Blob 导出表格(包括表格样式,金额千分位格式,并且符合excel表格的合并机制)

方法一:使用xlsx xlsx-style 插件

1.1 导入插件

npm install xlsx --save
npm install xlsx-style --save

1.2  解决xlsx-style运行报错问题,在vue.config.js中写入

module.exports = {
	configureWebpack: {
    	externals: {
      		'./cptable': 'var cptable'
    	}
  	}
}

1.3 核心代码

// 根据dom导出表格
  exportToExcel(idSelector, fileName, c = 1,s=1) { //idSelector要导出的表格ID名字,fileName 表格名称 c 要处理的数据位置列 s 这个就是行位置
    // 设置导出的内容是否只做解析,不进行格式转换     false:要解析, true:不解析
    const xlsxParam = { raw: true }
    let table = document.querySelector(idSelector).cloneNode(true);

    // 因为element-ui的表格的fixed属性导致多出一个table,会下载重复内容,这里删除掉
    if (table.querySelector('.el-table__fixed-right'))
      table.removeChild(table.querySelector('.el-table__fixed-right'));
    if (table.querySelector('.el-table__fixed'))
      table.removeChild(table.querySelector('.el-table__fixed'));

    const wb = XLSX.utils.table_to_book(table, xlsxParam)
    let range = XLSX.utils.decode_range(wb.Sheets['Sheet1']['!ref']);
    let cWidth = [];
    for (let C = range.s.c; C < range.e.c; ++C) {   //SHEET列
      let len = 100; //默认列宽
      let len_max = 400; //最大列宽
      for (let R = range.s.r; R <= range.e.r; ++R) {  //SHEET行
        let cell = { c: C, r: R };             //二维 列行确定一个单元格
        let cell_ref = XLSX.utils.encode_cell(cell);  //单元格 A1、A2
        if (wb.Sheets['Sheet1'][cell_ref]) {
          if (cell.c > c && cell.r > s) { // 从第一列,第一行开始处理 (默认表格从下标0开始)
            wb.Sheets['Sheet1'][cell_ref].t = 'n' // 表格类型n 为number类型 s 为string类型
            // 指定哪一列的样式
            wb.Sheets['Sheet1'][cell_ref].s = { // 数字上下居中左右居右
              alignment: {
                horizontal: 'right',
                vertical: 'center',
              },
              border: {
                top: { style: 'thin' },
                bottom: { style: 'thin' },
                left: { style: 'thin' },
                right: { style: 'thin' }
              }
            };
          } else {
            wb.Sheets['Sheet1'][cell_ref].s = {
              alignment: {
                horizontal: 'center',
                vertical: 'center',
              },
              border: {
                top: { style: 'thin' },
                bottom: { style: 'thin' },
                left: { style: 'thin' },
                right: { style: 'thin' }
              }
            };
          }
          // 在这里设置数字格式为货币类型(因为项目中的数据导入之前是做过处理的字符串问题,这里根据自己的数据需求进行处理)
          if (wb.Sheets['Sheet1'][cell_ref].t === 'n') {
            if(typeof wb.Sheets['Sheet1'][cell_ref].v === 'string'){
              wb.Sheets['Sheet1'][cell_ref].v = wb.Sheets['Sheet1'][cell_ref].v.replace(/,/g,"")
              let value = parseFloat(wb.Sheets['Sheet1'][cell_ref].v);
              if (!isNaN(value)) {
                wb.Sheets['Sheet1'][cell_ref].z = '#,##0.00'; // 设置为货币类型(保留千分位)
              }
            }
          }
          //动态自适应:计算列宽
          let va = JSON.parse(JSON.stringify(wb.Sheets['Sheet1'][cell_ref].v));
          var card1 = JSON.parse(JSON.stringify(va)).match(/[\u4e00-\u9fa5]/g); //匹配中文
          var card11 = "";
          if (card1) {
            card11 = card1.join("")
          }
          var card2 = JSON.parse(JSON.stringify(va)).replace(/([^\u0000-\u00FF])/g, "");  //剔除中文
          let st = 0;
          if (card11) {
          //中文字节码长度
            st += card11.length * 20  //中文字节码长度
          }
          if (card2) {
            //非中文字节码长度
            st += card2.length * 10  //非中文字节码长度
          }
          if (st > len) {
            len = st;
          }
        }
      }
      if (len > len_max) {//最大宽度
        len = len_max;
      }
      cWidth.push({ 'wpx': len });     //列宽
    }
    wb.Sheets['Sheet1']['!cols'] = cWidth
    // binary
    const wbout = XLSXStyle.write(wb, { bookType: 'xlsx', bookSST: false, type: 'binary' })
    try {
      saveAs(new Blob([this.s2ab(wbout)], { type: 'application/octet-stream' }), `${fileName}.xlsx`)
    } catch (e) {
      if (typeof console !== 'undefined') {
        console.log(e, wbout)
      }
    }
    return wbout
  },
s2ab(s) {
    var buf = new ArrayBuffer(s.length);
    var view = new Uint8Array(buf);
    for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
    return buf;
  },

方法二:使用二进制流 new Blob 导出

exportFnHtml(idName, reportName) {
    // 使用outerHTML属性获取整个table元素的HTML代码(包括<table>标签),然后包装成一个完整的HTML文档,设置charset为urf-8以防止中文乱码 $("#out-table .is-center")
    let otable = document.querySelector(idName)
    let newTable = otable.cloneNode(true)

    newTable.style.border = "1px solid #000"
    let obox = newTable.getElementsByClassName("is-center")
    let rbox = newTable.getElementsByClassName("is-right")
    
    //加空格转成字符串
    for (let index = 0; index < obox.length; index++) {
      obox[index].getElementsByClassName("cell")[0].innerHTML = "<span>&nbsp;</span>" + obox[index].getElementsByClassName("cell")[0].innerHTML

    }
    let otd = newTable.getElementsByTagName("td");
    let oth = newTable.getElementsByTagName("th");
    let othcopy = []
    for (let index = 0; index < oth.length; index++) {
      if (oth[index].getAttribute('class') != "el-table__cell gutter") {
        othcopy.push(oth[index])
      }
    }
    styleFn(otd);
    styleFn(othcopy);
    function styleFn(oDom, sign) {
      if (sign) {
        for (let i = 0; i < oDom.length; i++) {
          oDom[i].style.border = "";
        }
        return;
      }
      for (let i = 0; i < oDom.length; i++) {
        oDom[i].style.border = "0.5px solid #444";
        oDom[i].style.background = "#fff"
      }
    }
    var html = "<html><head><meta charset='utf-8' /></head><body>" + newTable.outerHTML + "</body></html>";
    // 实例化一个Blob对象,其构造函数的第一个参数是包含文件内容的数组,第二个参数是包含文件类型属性的对象
    var blob = new Blob([html], { type: "application/vnd.ms-excel; charset=UTF-8" });
    let a = document.createElement('a');
    // 利用URL.createObjectURL()方法为a元素生成blob URL
    a.href = URL.createObjectURL(blob);
    // 设置文件名
    a.download = reportName;
    otable.appendChild(a)
    a.click()
  },

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值