目录
前言:
技术选型:
主要功能点:
核心代码:
完整代码:
开发文档
在前后端分离开发为主流的时代,很多时候,excel导出已不再由后端主导,而是把导出的操作移交到了前端。本文在全局导出组件封装上,保持了高度的扩展性,无论大家用的是element组件库还是antd vue的组件库或者其他的组件库,都容易进行更换。
vue + antd vue + sheetjs
前端导出excel导出,需借助第三方插件,目前两款导出最为主流。
一款是sheetjs,优点支持多种excel格式,但是官方文档全是英文
SheetJS Community Edition | SheetJS Community Edition
一款是exceljs,优点是中文文档很全,缺点是导出格式受限,仅支持部分格式
https://github.com/exceljs/exceljs/blob/master/README_zh.md
因公司业务需要,用户需支持多种excel的格式,所以本文笔者主要针对sheetjs进行封装调用。
// 文件名称
const filename = fileName;
//Excel第一个sheet的名称
const ws_name = sheetName;
// 创建sheet
const ws = XLSX.utils.aoa_to_sheet([this.tableTitle]);
//添加数据
XLSX.utils.sheet_add_json(ws, apiData, {
skipHeader: true,
origin:origin
});
// 创建wokbook
const wb = XLSX.utils.book_new();
// 将数据添加到工作薄
XLSX.utils.book_append_sheet(wb, ws, ws_name);
// 导出文件
XLSX.writeFile(wb, filename);
npm i xlsx
ExportExcelComponent.vue
导出excel
重新导出
继续导出
关闭
App.vue
测试表格导出
Dropdown
1st menu item
2nd menu item
3rd item
request.js
const asyncDataApi = (listquery) => {
console.log("params", listquery);
// 模拟异步请求接口
return new Promise((resolve, reject) => {
setTimeout(() => {
const data = [];
for (let i = listquery.page * 100; i < (listquery.page + 1) * 100; i++) {
const obj = {
id: i - 99,
name: "姓名" + i,
age: 20 + i,
hobby:
"赵客缦胡缨,吴钩霜雪明。银鞍照白马,飒沓如流星。十步杀一人,千里不留行。事了拂衣去,深藏身与名。闲过信陵饮,脱剑膝前横。将炙啖朱亥,持觞劝侯嬴。" +
i,
sex: "男" + i,
birthday: "2020-01-01",
createTime: "1701155392",
updateTime: "2020-01-01",
remark: "备注" + i,
status: "1" + i,
};
// let newObj = {};
// for (var a = 1; a < 500; a++) {
// for (let k in obj) {
// newObj[k + a] = obj[k];
// }
// }
// data.push(newObj);
data.push(obj);
}
resolve({
data,
code: 200,
msg: "请求成功",
paginator: {
page: 1000,
size: 100,
total: 100000,
currentPage: listquery.page,
},
});
}, 100);
});
};
export { asyncDataApi };
如果不采用自定义dom的话,直接点击默认的按钮可直接导出表格数据; 如果采用自定义dom的话,通过ref实例调用子组件内的startExport方法,执行导出操作
导出excel
属性如下
参数 | 说明 | 类型 | 默认值 |
---|---|---|---|
listQuery | 请求参数 | Object | {} |
asyncDataApi | 请求数据的api函数 | Function | 必传 |
tableTitleData | 导出的数据表的表头 | Array | 必传 |
isCustom | 是否自定义dom,如果采用插槽,需要开启该属性,否则dom为默认button;可以传递 v-slot:custom 来自定义 dom。 |
Boolean | false |
modelTitle | 模态框标题 | String | "导出excel" |
multiFileSize |
拆分成每个表多少条数据,需要搭配isSplit属性一起使用 | Number | 10e3 |
filename | 导出的excel的表名 | String | "Excel" + new Date().getTime() |
ws_name | sheet名 | String | "Sheet" |
filterFunction | 自定义过滤函数;可在业务层处理数据格式,如时间格式化等 | Function(data) | null |
filterFunction怎么使用
导出excel
导出表格数据为空是什么情况?
因为导出的表格数据的顺序和标题的顺序并不一定是一致的,所以在组件内部做了映射排序,一定要确保传入的标题数据在调用导出接口之前执行。如果传递的标题有误,在进行映射的时候,这时标题和表格数据并不匹配,那么就会出现数据映射为空的情况
Promise Error:"asyncDataApi is required"
当传递给组件的后端api需要在点击dom后赋值再传递的时候,一定要确保在导入后端api之后再调用组件内的导出方法,否则因为后端api还没传递过去就调用,然后抛错或者导出异常
正确示例:
async handleClick() {
await (this.asyncDataApi = asyncDataApi);
this.$refs.export.getTableData();
},
后端导出表格api数据返回格式
因该组件为全局组件,方便以后复用,需与后端协商规定好数据导出的格式。以下为笔者的公司,与后端同事协商的数据格式。大家可根据自己公司需要,更改以上源码中后端返回值字段。
//后端返回数据结构
{
"status": true,
"data": [
{...},
{...},
],
"paginator": {
"currentPage": 1,
"total": 200,
"size": 20,
"page": 10
}
}