1. 纯前端实现导出
安装file-saver和xlsx
file-saver: 用于在浏览器中触发文件的保存下载(保存为本地文件)。
使用场景: 当已经在 JavaScript 中生成了文件(如 Blob 对象),并想让用户保存它时使用。
npm install file-saver
xlsx: 读写 Excel 文件(.xlsx),支持从数据生成 Excel 文件或从 Excel 文件中解析数据。
使用场景:从前端导出 JSON 为 .xlsx 文件;从 .xlsx 文件中读取数据进行展示或处理。
npm install xlsx
导出element-plus表格,支持勾选导出,不勾选默认导出全部数据:
只导出勾选项:
<template><el-button:disabled="tableData.length === 0"@click="handleExport()"style="margin-bottom: 6px">导出</el-button><el-table:data="tableData"style="width: 100%"@selection-change="handleSelectionChange"><el-table-column type="selection" width="55" /><el-table-column prop="date" label="日期" width="120"></el-table-column><el-table-column prop="name" label="姓名" width="120" /><el-table-column prop="address" label="地址" /><el-table-column prop="status" label="状态" width="85"><template #default="{ row }"><el-tag effect="dark" size="small" :type="getStatusTagType(row.status)" disable-transitions>{{ getStatusText(row.status) }}</el-tag></template></el-table-column></el-table>
</template><script setup>
import { ref, computed } from 'vue';
import * as XLSX from 'xlsx';
import FileSaver from 'file-saver';const tableData = [{date: '2016-05-04',name: 'Aleyna Kutzner',address: 'Lohrbergstr. 86c, Süd Lilli, Saarland',status: 0,},{date: '2016-05-03',name: 'Helen Jacobi',address: '760 A Street, South Frankfield, Illinois',status: 1,},{date: '2016-05-02',name: 'Brandon Deckert',address: 'Arnold-Ohletz-Str. 41a, Alt Malinascheid, Thüringen',status: 2,},{date: '2016-05-01',name: 'Margie Smith',address: '23618 Windsor Drive, West Ricardoview, Idaho',status: 1,},
];
const mergeRows = ref([]);
const STATUS_TEXT = {0: '未处理',1: '已处理',2: '已取消',
};
const STATUS_TAG_TYPE = {0: 'danger',1: 'primary',2: 'info',
}
const getStatusText = computed(() => status => STATUS_TEXT[status]);
const getStatusTagType = computed(() => status => STATUS_TAG_TYPE[status]);const handleSelectionChange = selection => {mergeRows.value = selection;
};const handleExport = async (fileName = 'export.xlsx') => {const originalData =mergeRows.value.length === 0 ? tableData : mergeRows.value;const headers = [{ key: 'date', title: '日期', width: 20 },{ key: 'name', title: '姓名', width: 30 },{ key: 'address', title: '地址', width: 60 },{ key: 'status', title: '状态', width: 20, formatter: getStatusText.value },];const data = originalData.map(row =>Object.fromEntries(headers.map(({ key, title, formatter }) => [title,formatter ? formatter(row[key]) : row[key],])));// 生成 Sheetconst worksheet = XLSX.utils.json_to_sheet(data);// 设置列宽worksheet['!cols'] = headers.map(({ width }) => ({ wch: width }));const workbook = XLSX.utils.book_new();XLSX.utils.book_append_sheet(workbook, worksheet);// 导出 Excelconst excelBuffer = XLSX.write(workbook, {bookType: 'xlsx',type: 'array',});const blob = new Blob([excelBuffer], { type: 'application/octet-stream' });FileSaver.saveAs(blob, fileName);// 浏览器将下载 export.xlsx文件
};
</script>
2. 从后端获取数据导出
- 情形1:后端返回链接的导出:
window.location.href
= 链接地址 - 情形2:返回二进制/base数据的导出:先将得到的数据转成二进制,再用
new Blob()
处理二进制生成文件,使用createObjectURL()
生成链接,创建a
标签元素模拟点击事件
async function handleExport() {const params = {selected_ids: mergeRows.value.map(row => row.id),};const res = await exportReservation(params);if (res.status===200) {// 返回的是base64编码const fileContent = res.data;// base64转为二进制const binaryString = atob(fileContent);const bytes = new Uint8Array(binaryString.length);for (let i = 0; i < binaryString.length; i++) {bytes[i] = binaryString.charCodeAt(i);}// 生成blobconst blob = new Blob([bytes], {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'});// 创建下载链接const url = window.URL.createObjectURL(blob);const a = document.createElement('a');a.href = url;a.download = 'xxx.xlsx';document.body.appendChild(a);a.click();// 清理window.URL.revokeObjectURL(url);document.body.removeChild(a);ElMessage.success('导出成功');} else {ElMessage.error('导出失败';}
}