el-table的导出下载并设置格式
一、背景
- Vue3+Ts+Element plus的项目,其中的表格是利用el-table创建的。目的是将该表格导出为Excel表格并且在表格导出后自带样式,方便查看。
- 需要安装file-saver、xlsx、xlsx-style包。file-saver是一个nodejs常用的文件保存包,支持多种浏览器。xlsx用于Excel表格中读取数据、生成数据的包。xlsx-style是xlsx的一个分支,主要目的是设置表格样式。
二、安装file-saver、xlsx和xlsx-style包
-
安装,在终端中分别输入以下代码。我用的包管理器是npm,如果你用的是pnpm或其他包管理器将npm换成pnpm即可。以下是三个包的文档链接:
file-saver:
https://www.npmjs.com/package/file-saver/v/2.0.0-rc.1
xlsx:
https://www.npmjs.com/package/xlsx
xlsx-style:
https://www.npmjs.com/package/xlsx-style//file-saver npm install file-saver --save //xlsx npm install xlsx //xlsx-style npm install xlsx-style --save
-
xlsx-style包中存在一些问题,安装后会报错。这里以本次导出表格为目的对其中的报错进行修改xlsx-style中的代码。
node_modules\xlsx-style\dist\cpexcel.js
//修改其中的807行为以下代码 /* var cpt = require('./cpt' + 'able'); */ var cpt = cptable; //修改
node_modules\xlsx-style\xlsx.js
//修改其中的第7行 /* var cptable, style_builder, QUOTE, _hashIndex; */ var cptable, style_builder, QUOTE, _hashIndex, _listIndex, style_builder;//修改
//修改其中的1340行 if(typeof jszip === 'undefined') jszip = require('./jszip.js');//修改 /*if(typeof jszip === 'undefined') jszip = require('./js'+'zip').JSZip; */
一般修改以上问题就可以使用了,但是这样直接修改包文件,在重装依赖即npm install后会报错,改起来也比较麻烦,所以尽量别改原文件而是直接在配置文件中进行修改会好很多,我这里只是一个测试所以没有在配置文件中改。
三、表格导出
-
创建一个表格导出按钮并添加点击事件
//<template>中 <el-button type="primary" @click="export">导出</el-button>
-
表格导出的前提是需要在标签中添加id属性
//<template>中 <el-table id="Table" :data="TableData"> ... </el-table>
-
导出方法,单元格样式属性见末尾
//<script setup lang="ts">中 import FileSaver from "file-saver"; import {utils} from "xlsx"; import XLSX from "xlsx-style"; function export() { //如果导出后多出空白行则修改rowspan,否则可不用 var tds = document.querySelectorAll(".el-table__footer td"); tds.forEach(td => td.setAttribute("rowspan", "1")); //从el-table表生成工作簿对象 //使用原始的格式,保留表格中的格式如%、小数末尾的0等 var workbook = utils.table_to_book(document.querySelector("#Table"), { raw: true }); //列宽,需要导出的表格有多少列这里的i就小于多少 for (let i = 1; i < 15; i++) { workbook.Sheets.Sheet1["!cols"].push({ wpx: 80 }); } //设置单元格样式 for (const key in workbook.Sheets.Sheet1) { if ( key !== "!cols" && key !== "!fullref" && key !== "!merges" && key !== "!ref" && key !== "!rows" ) { //这里的s就是具体的样式,如果想设置不一样的样式可以看xlsx-style文档 workbook.Sheets.Sheet1[key].s = { //边框 border: { top: {style: "thin"}, bottom: {style: "thin"}, left: {style: "thin",}, right: {style: "thin",} }, //对齐 alignment: { horizontal: "center", vertical: "center", wrapText: true } }; } } //修改合并单元格样式 let arr = ["A","B","C","D","E","F","G","H","I","J","K","L","M","N", "O","P","Q","R","S","T","U","V","W","X","Y","Z"]; //由于导出时合并单元格只识别左上角的单元格,合并单元格中其他单元格 //并不会存在,所以需要识别合并单元格中除左上角单元格外的单元格并添加 //带样式的单元格到其中,不理解可以看四中的第2点。 for (let item of workbook.Sheets.Sheet1["!merges"]) { let style = {border: { top: {style: "thin"}, bottom: {style: "thin"}, left: {style: "thin",}, right: {style: "thin",} }, alignment: { horizontal: "center", vertical: "center", wrapText: true }}; let merge_s = { t: "s", v: "", s: style}; if (item.s.c == item.e.c) { //纵向合并,其中c为字母r为数字 let star = item.s.r; let end = item.e.r; for (let i = star + 1; i <= end; i++) { workbook.Sheets.Sheet1[arr[item.s.c] + (i + 1)] = merge_s; } } else { //横向合并 let star = item.s.c; let end = item.e.c; for (let i = star; i < end; i++) { workbook.Sheets.Sheet1[arr[i + 1] + Number(item.s.r + 1)] = merge_s; } } } //将表格数据中的字符串转ArrayBuffer function 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; } //这里的属性可以参考xlsx-style文档 var wbout = XLSX.write(workbook, { bookType: "xlsx", bookSST: false, type: "binary" }); try { FileSaver.saveAs( new Blob([s2ab(wbout)], { type: "application/octet-stream" }), "数据总览.xlsx" ); } catch (e) { if (typeof console !== "undefined") console.log(e, wbout); } }
四、对表格导出中workbook的认识
-
见以下代码,workbook就是一个数据对象,其中包含表格的所有数据、以及各种属性,修改其中的各种属性就可以达到修改Excel表格的目的。
-
workbook对象结构如下,其中的Sheet1是对映Excel文件的第一个Sheet。
—!cols属性主要用于对列宽的调整;
—!rows属性是对行的调整;
—!fullref属性是指Sheet1中的有数据的区域;
—!merges属性用于记录合并单元格。如{e: {r: 2, c: 0},s: {r: 0, c: 0}}其中的s 指开始单元格,e指结束单元格;r为行号数字,c为列号字母;这里表示的是合并单元格A1到A3;
—A1: {t: ‘数据类型’, v: ‘内容’, s: {样式}},该属性为单元格属性包含的属性如其中所示,t通常为s即字符串,v指具体表格内容,s保存样式修改s就可以达到修改样式的目的。 -
注意:下面的workbook对象中Sheet1中A1过后直接就到A4,而没有A2、A3,这是因为它是!merges中记录的合并单元格A1-A3。所以我们在设置单元格样式时如果仅仅是对Sheet1中存在的单元格设置样式,会导致合并单元格的样式没有。所以在设置样式时我们需要单独对合并单元格进行处理,在Sheet1中添加因为合并而不存在的单元格A2和A3然后设置样式并将内容设置为空,这样就完成了表格样式的修改。
//workbook对象的具体内容 { Props: { Application: "SheetJS" SheetNames: ['Sheet1'] Worksheets: 1} SSF: { 0: "General" 1: "0" ...} SheetNames: {[ "Sheet1"]} Sheets: { Sheet1: { !cols: [{wpx: 50}, ... {wpx: 50}] !fullref: "A1:D5" !merges: [{e: {r: 2, c: 0},s: {r: 0, c: 0}}, ... {…}] !ref: "A1:D5" !rows: [] A1: {t: '数据类型', v: '内容', s: {样式}} A4: {t: 's', v: '', s: {…}} ... D5: {t: 's', v: '', s: {…}}} } } }
五、单元格样式属性
图片来自官网文档