目录
一、背景描述
有些业务常见,例如前端已经获取到表格的所有数据了,并且后端技术人员比较繁忙,总会提出前端分页,前端排序,甚至前端导出数据为excel的需求,所以这个文章就记录一下这个功能怎么实现。实现的功能:导出表格的数据为Excel或cvs,并且前端分页加排序。(不引入第三方库实现导出功能)
二、功能分析
不引入第三方库,所以就前端生成Excel并导出。
前端生成 Excel 文件的方式:首先获取表格数据内容,并对表头进行处理,以确保没有额外的空白单元格。然后,它构建了一个包含表格内容的 HTML 文件,其中包括 Excel 文件所需的一些元信息和样式。接下来,它将该 HTML 文件转换为 Blob 对象,然后通过创建链接并触发下载的方式,实现了文件的下载。
分页排序就比较简单了,只要复制一份表格数据,处理并展示这个数据就行,原始的数据可以用于导出数据。
如下:
三、详细开发
1.导出为excel
首先需要一个表格和导出按钮,如下:
<el-col :span="4" >
<el-button type="primary" @click="exportToExcel">导出</el-button>
</el-col>
<el-table
:data="sortedAndPaginatedVerificationTableData"
stripe
border
ref="tableRef"
@sort-change="handleSortChange"
>
<el-table-column prop="age" label="年龄" width="150" sortable>
</el-table-column>
<el-table-column prop="status" label="状态" width="120" sortable>
</el-table-column>
<el-table-column
prop="message"
label="信息"
sortable
>
</el-table-column>
</el-table>
接着导出功能的实现,2种方式:
第一种,可忽略不看。
//导出Excel
exportToExcel(){
//第一种方式
// 获取表格内容
const excelContent = this.$refs.tableRef.$el.innerHTML;
// 处理表头,确保没有额外的空白单元格
const headerElement = document.createElement('div');
headerElement.innerHTML = excelContent;
const headerCells = headerElement.querySelectorAll('th');
// 移除最后一个空单元格
if (headerCells.length > 0) {
const lastCell = headerCells[headerCells.length - 1];
lastCell.parentNode.removeChild(lastCell);
}
// 构建 Excel 文件内容
let excelFile = `
<html xmlns:o='urn:schemas-microsoft-com:office:office' xmlns:x='urn:schemas-microsoft-com:office:excel' xmlns='http://www.w3.org/TR/REC-html40'>
<head>
<!--[if gte mso 9]>
<xml>
<x:ExcelWorkbook>
<x:ExcelWorksheets>
<x:ExcelWorksheet>
<x:Name>{worksheet}</x:Name>
<x:WorksheetOptions>
<x:DisplayGridlines/>
</x:WorksheetOptions>
</x:ExcelWorksheet>
</x:ExcelWorksheets>
</x:ExcelWorkbook>
</xml>
<![endif]-->
<style>
td{border: .5pt solid;}
</style>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
${headerElement.innerHTML}
</body>
</html>
`;
// 创建 Blob 对象
const blob = new Blob([excelFile], { type: 'application/vnd.ms-excel' });
// 创建链接并触发下载
const link = document.createElement("a");
link.href = URL.createObjectURL(blob);
link.download = '表格.xlsx'; // 设置默认文件名
link.style.display = "none";
document.body.appendChild(link);
link.click();
window.URL.revokeObjectURL(link.href);
document.body.removeChild(link);
}
第二种:
//导出Excel
exportToExcel(){
//第二种方式
// 获取表格数据
const tableData = this.tableData;
// 构建 Excel 文件内容
let excelContent = `<html><head><meta charset="UTF-8"></head><body><table border="1">`;
// 添加表头
excelContent += '<tr>';
for (const column of this.$refs.tableRef.columns) {
if (column.property) {
excelContent += `<th>${column.label}</th>`;
}
}
excelContent += '</tr>';
// 添加表格数据
for (const row of tableData) {
excelContent += '<tr>';
for (const column of this.$refs.tableRef.columns) {
if (column.property) {
excelContent += `<td>${row[column.property]}</td>`;
}
}
excelContent += '</tr>';
}
// 构建完整的 Excel 文件内容
excelContent += '</table></body></html>';
// 创建 Blob 对象
const blob = new Blob([excelContent], { type: 'application/vnd.ms-excel' });
// 创建链接并触发下载
const link = document.createElement("a");
link.href = URL.createObjectURL(blob);
link.download = '表格.xlsx'; // 设置默认文件名
link.style.display = "none";
document.body.appendChild(link);
link.click();
window.URL.revokeObjectURL(link.href);
}
这里tableData是表格的原始数据,如果前端已经获取到表格的所有数据,就可以对整个数据进行导出,也就是推荐第二种方式,第一种方式可以对表格样式进行控制,但是数据是考虑当前页面的表格数据,也就是本页数据的导出,所以后来我摒弃了第一种方式,直接使用的第二种方式。
第二种方式的好处:
首先,它获取表格数据并遍历每一行,以构建 Excel 文件内容。
在构建表头时,它遍历了表格的列属性,以获取每一列的标签(label),并添加到表头中,不用控制表格过滤空白单元格,这是第一种的弊端。
2.导出为cvs
let csvContent = "data:text/csv;charset=utf-8,";
csvContent += "年龄,状态,信息\n"; // 添加表头
// 添加数据行
this.verificationTableData.forEach(row => {
let csvRow = [];
csvRow.push(row.age);
csvRow.push(row.status);
csvRow.push(row.message);
csvContent += csvRow.join(",") + "\n";
});
// 创建下载链接
const encodedUri = encodeURI(csvContent);
const link = document.createElement("a");
link.setAttribute("href", encodedUri);
link.setAttribute("download", "data.csv");
document.body.appendChild(link);
// 触发点击下载
link.click();
document.body.removeChild(link);
3.前端排序和分页
其实我已经写过不少这个功能,为何还要再提,只是因为我在写上面的功能时,无法沿用之前的写法能实现这个功能,所以记录一下。
sortColumn: '', // 存储当前排序的列
sortOrder: '', // 存储当前排序的顺序
computed: {
sortedAndPaginatedVerificationTableData() {
// console.log("sortedAndPaginatedVerificationTableData")
let data = this.tableData.slice();
if(data.length<1){
return []
}
// console.log("sortedAndPaginatedVerificationTableData",'com')
// 根据排序规则进行排序
if (this.sortColumn && this.sortOrder) {
data.sort((a, b) => {
const valueA = a[this.sortColumn];
const valueB = b[this.sortColumn];
if (this.sortOrder === 'ascending') {
if (valueA > valueB) return 1;
if (valueA < valueB) return -1;
return 0;
} else {
if (valueA > valueB) return -1;
if (valueA < valueB) return 1;
return 0;
}
});
}
// 如果需要分页,则进行分页操作
if (this.page) {
const startIndex = (this.page.page - 1) * this.page.limit;
const endIndex = this.page.page * this.page.limit;
data = data.slice(startIndex, endIndex);
}
return data;
}
},
handleSortChange(column, order) {
// 更新当前排序的列和顺序
this.sortColumn = column.prop;
this.sortOrder = column.order;
console.log('change',column,order,this.sortColumn,this.sortOrder );
},
四、总结
使用 HTML 表格和 Blob,将数据动态生成为 HTML 表格,然后通过 HTML5 的 Blob 和 URL.createObjectURL 方法来创建一个链接,最后让用户点击链接下载生成的 Excel 文件。虽然不是真正的 Excel 文件,但可以在大多数情况下满足导出需求。