4行代碼實(shí)現(xiàn)vue + element ui的表格數(shù)據(jù)導(dǎo)出為xlsx文件

需求說明

前端頁(yè)面通過表格呈現(xiàn)查詢數(shù)據(jù),并由一個(gè)按鈕點(diǎn)擊事件將表格的數(shù)據(jù)以xlsx的文件格式導(dǎo)出下載。

開發(fā)環(huán)境

Chrome + vue 2.0 + Element UI

方案1:XLSX + FILE-SAVER

由于文件下載需求的普遍性,以及vue和Element的流行性,網(wǎng)上類似的方案很多。稍作整理后的形式如下:

 // 導(dǎo)出按鈕綁定的函數(shù)
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;
}

該函數(shù)流程大致為:

  1. 通過ID找到表格
  2. 利用XLSX的table_to_book方法將表格數(shù)據(jù)直接生成到工作簿
  3. 將工作簿包裝為blob對(duì)象
  4. 通過FileSaver實(shí)現(xiàn)文件保存功能

問題1:可能導(dǎo)出重復(fù)數(shù)據(jù)

當(dāng)使用Element UI的el-table中的fixed屬性時(shí),實(shí)際生成了2張表格,因此以上方案導(dǎo)出的數(shù)據(jù)會(huì)出現(xiàn)重復(fù)的現(xiàn)象。就像這樣:


重復(fù)的數(shù)據(jù)

既然原因很清楚了,那么這個(gè)問題的解決辦法也容易找到:在生成工作簿的時(shí)候,首先去除帶有fix屬性的表格,在工作簿對(duì)象生成后再添加上。
這樣,生成工作簿的代碼更新為:

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:分頁(yè)數(shù)據(jù)只導(dǎo)出頁(yè)面顯示的部分

如果表格存在分頁(yè),上述方法導(dǎo)出的是當(dāng)前顯示的部分。網(wǎng)上也有幾種解決辦法:

  • 前端隱藏一個(gè)全量的table,專門用于導(dǎo)出(個(gè)人不推薦)。
  • 導(dǎo)出的時(shí)候臨時(shí)修改pageSize,使全量數(shù)據(jù)都在表格上。完成后還原。

這兩個(gè)我都沒嘗試,也就不貼代碼了,通過搜索都可以找到。

方案2:只使用XLSX解決問題

之前兩個(gè)問題的解決辦法要么觸發(fā)了前端變更的操作,要么保存了多余的內(nèi)容。雖然能解決問題,但總有些變扭。
重新看了看SheetJS項(xiàng)目的文檔,發(fā)現(xiàn)有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"]});

如果不顯式定義列名,則以第一個(gè)對(duì)象的Object.keys作為列名。

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

這不正和el-table的表單數(shù)據(jù)格式一模一樣么。本地已經(jīng)有tableData,且是全量數(shù)據(jù),不存在分頁(yè)問題,直接用tableData加上json_to_sheet方法生成sheet便可。但這個(gè)方法返回的是worksheet,而非workbook,因此需要添加到一個(gè)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');
    }

代碼可以如此簡(jiǎn)潔,且用不著file-saver的原因是,其實(shí)writeFile方法包裝了很多行為,包括使瀏覽器生成文件的鏈接并強(qiáng)制點(diǎn)擊,觸發(fā)文件保存的動(dòng)作等。

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庫(kù)
  2. Element-ui組件庫(kù)Table表格導(dǎo)出Excel表格
  3. 記element + xlsx 導(dǎo)出表格數(shù)據(jù)重復(fù)的坑
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容