4行代码实现vue + element ui的表格数据导出为xlsx文件

需求说明

前端页面通过表格呈现查询数据,并由一个按钮点击事件将表格的数据以xlsx的文件格式导出下载。

开发环境

Chrome + vue 2.0 + Element UI

方案1:XLSX + FILE-SAVER

由于文件下载需求的普遍性,以及vue和Element的流行性,网上类似的方案很多。稍作整理后的形式如下:

 // 导出按钮绑定的函数
exportXLSX() {
    // 从表格生成workbook
    let wb = XLSX.utils.table_to_book(document.querySelector('#tableID'));
    let wbout = XLSX.write(wb, {
        bookType: "xlsx",
        bookSST: true,
        type: "array"
    });
    try {
    // 下载
        let b = new Blob([wbout], { type: "application/octet-stream" });
        FileSaver.saveAs(b, "filename.xlsx");
    } catch (e) {
        if (typeof console !== "undefined") {
            console.log(e, wbout);
        }
    }
    return wbout;
}

该函数流程大致为:

  1. 通过ID找到表格
  2. 利用XLSX的table_to_book方法将表格数据直接生成到工作簿
  3. 将工作簿包装为blob对象
  4. 通过FileSaver实现文件保存功能

问题1:可能导出重复数据

当使用Element UI的el-table中的fixed属性时,实际生成了2张表格,因此以上方案导出的数据会出现重复的现象。就像这样:


重复的数据

既然原因很清楚了,那么这个问题的解决办法也容易找到:在生成工作簿的时候,首先去除带有fix属性的表格,在工作簿对象生成后再添加上。
这样,生成工作簿的代码更新为:

let fix = document.querySelector('.el-table__fixed');
if (fix) {
    let wb = XLSX.utils.table_to_book(document.querySelector('#tableID').removeChild(fix));
    document.querySelector('#tableID').appendChild(fix);
} else {
    let wb = XLSX.utils.table_to_book(document.querySelector('#tableID'));
}

问题2:分页数据只导出页面显示的部分

如果表格存在分页,上述方法导出的是当前显示的部分。网上也有几种解决办法:

  • 前端隐藏一个全量的table,专门用于导出(个人不推荐)。
  • 导出的时候临时修改pageSize,使全量数据都在表格上。完成后还原。

这两个我都没尝试,也就不贴代码了,通过搜索都可以找到。

方案2:只使用XLSX解决问题

之前两个问题的解决办法要么触发了前端变更的操作,要么保存了多余的内容。虽然能解决问题,但总有些变扭。
重新看了看SheetJS项目的文档,发现有json_to_sheet方法,官方的示例如下:

var ws = XLSX.utils.json_to_sheet([
  { S:1, h:2, e:3, e_1:4, t:5, J:6, S_1:7 },
  { S:2, h:3, e:4, e_1:5, t:6, J:7, S_1:8 }
], {header:["S","h","e","e_1","t","J","S_1"]});

如果不显式定义列名,则以第一个对象的Object.keys作为列名。

The default column order is determined by the first appearance of the field using Object.keys

这不正和el-table的表单数据格式一模一样么。本地已经有tableData,且是全量数据,不存在分页问题,直接用tableData加上json_to_sheet方法生成sheet便可。但这个方法返回的是worksheet,而非workbook,因此需要添加到一个workbook。最后使用workbook的writeFile方法即可完成下载。最终代码如下:

exportXLSX() {
        let ws = XLSX.utils.json_to_sheet(this.tableData);
        let wb = XLSX.utils.book_new();
        XLSX.utils.book_append_sheet(wb, ws, 'sheetname');
        return XLSX.writeFile(wb, 'filename.xlsx');
    }

代码可以如此简洁,且用不着file-saver的原因是,其实writeFile方法包装了很多行为,包括使浏览器生成文件的链接并强制点击,触发文件保存的动作等。

XLSX.writeFile wraps a few techniques for triggering a file save:

  • URL browser API creates an object URL for the file, which the library uses by creating a link and forcing a click. It is supported in modern browsers.
  • msSaveBlob is an IE10+ API for triggering a file save.
  • IE_FileSave uses VBScript and ActiveX to write a file in IE6+ for Windows XP and Windows 7. The shim must be included in the containing HTML page.

不知道这样的兼容性如何,至少Chrome 80版本完全可行。

参考

  1. SheetJS js-xlsx的git库
  2. Element-ui组件库Table表格导出Excel表格
  3. 记element + xlsx 导出表格数据重复的坑

你可能感兴趣的:(4行代码实现vue + element ui的表格数据导出为xlsx文件)