记element + xlsx 导出表格数据重复的坑

137 阅读2分钟

在使用elementui做管理平台时遇到导出表格的需求,网上有很多解决方案,最多的就是使用xlsx + FileSaver 将页面上的表格转换成excel book。

这个过程中遇到过两个坑,记录一下。

用到的插件:

// 安装xlsx filesaver

 npm install --save xlsx file-saver
 

封装了一下工具方法

// 纯前端导出   el标识元素id,name为导出文件名
export function exportFileBySelf(el, name) {
  let xlsxParam = { raw: true }
  const wb = XLSX.utils.table_to_book(document.querySelector(`${el}`),xlsxParam);
  const wbout = XLSX.write(wb, {
    bookType: "xlsx",
    bookSST: true,
    type: "array"
  });
  try {
    FileSaver.saveAs(
      new Blob([wbout], { type: "application/octet-stream" }),
      `${name}.xlsx`
    );
    Message({
      message: "导出成功~",
      type: "success"
    });
  } catch (e) {
    if (typeof console !== "undefined") {
      Message({
        message: "导出失败",
        type: "error"
      });
      console.log(e, wbout);
    }
  }
  return wbout;
}

然而导出一份表格的时候发现一样的数据导了两遍。表头也是两遍

把所有的数据全部都查了一遍发现,我的数据没有重复,展示的table也无重复,再查看element table生成的代码发现: 罪魁祸首是: 如果使用了el-table的fixed属性来让某一列固定,但elementui的实现方式是:创建了两个tabledom,通过一个隐藏一个显示来实现交互效果。当我导出整个el-table 就会将两个div内的table都导出,导致数据重复。 原文链接:www.taodudu.cc/news/show-1…

所以我针对这种情况又做了以下处理:

  export const exportTb = (id, title) => {
    /* generate workbook object from table */
    // 判断要导出的节点中是否有fixed的表格,如果有,转换excel时先将该dom移除,然后append回去
     【重点】
    var fix = document.querySelector('.el-table__fixed');
    var wb;
    if (fix) {wb = XLSX.utils.table_to_book(document.querySelector(id).removeChild(fix));
    document.querySelector(id).appendChild(fix);
    } else {
    wb = XLSX.utils.table_to_book(document.querySelector(id));
    }
    【重点】
    /* get binary string as output */
    var wbout = XLSX.write(wb, 
    {bookType: 'xlsx',bookSST: true,type: 'array'});
    try {FileSaver.saveAs(new Blob([wbout], 
    {type: 'application/octet-stream'}),title);
    } catch (e) {
    if (typeof console !== 'undefined') 
    console.log(e, wbout);}
    return wbout;
    };

当然,也可以直接去掉fixed。看个人需求。

还有一个问题是,如果表格中用了slot-scope插槽,然后又搞了条件判断,比如

<template slot-scope="scope"> 
<span v-show="scope.row.sex == 1">男</span>
<span v-show="scope.row.sex == 2">女</span>
</template>

如果用v-show,就会导致两个都导出到单元格,因为v-show只是隐藏,dom元素实际还是存在的。全部改为v-if即可解决此问题。