<template>
<div>
<!-- 更复杂的 HTML 表格 -->
<table class="styled-table" ref="table">
<thead>
<tr>
<th rowspan="3">姓名</th>
<th rowspan="3">年龄</th>
<th colspan="4">成绩</th>
<th rowspan="3">备注</th>
</tr>
<tr>
<th colspan="2">期中考试</th>
<th colspan="2">期末考试</th>
</tr>
<tr>
<th>数学</th>
<th>英语</th>
<th>数学</th>
<th>英语</th>
</tr>
</thead>
<tbody>
<tr>
<td rowspan="2" class="name-cell">张三</td>
<td rowspan="2">20</td>
<td>85</td>
<td>90</td>
<td>92</td>
<td>95</td>
<td rowspan="2" class="remark-cell">表现良好</td>
</tr>
<tr>
<td>88</td>
<td>92</td>
<td>94</td>
<td>97</td>
</tr>
<tr>
<td class="name-cell">李四</td>
<td>22</td>
<td>88</td>
<td>92</td>
<td>94</td>
<td>97</td>
<td class="remark-cell">进步明显</td>
</tr>
<tr>
<td class="name-cell">王五</td>
<td>21</td>
<td>80</td>
<td>85</td>
<td>88</td>
<td>90</td>
<td class="remark-cell">需努力</td>
</tr>
<tr>
<td class="name-cell">赵六</td>
<td>23</td>
<td>90</td>
<td>95</td>
<td>92</td>
<td>96</td>
<td class="remark-cell">优秀</td>
</tr>
</tbody>
</table>
<!-- 下载按钮 -->
<button @click="exportToExcel">导出到 Excel</button>
</div>
</template>
<script>
import { ref } from 'vue';
import ExcelJS from 'exceljs';
export default {
name: 'TableToExcel',
setup() {
const table = ref(null);
const exportToExcel = async () => {
const rows = table.value.querySelectorAll('tr');
const workbook = new ExcelJS.Workbook();
const worksheet = workbook.addWorksheet('Sheet1');
let rowIndex = 1;
const mergeCellsList = [];
const rowSpans = []; // 用于跟踪跨行的单元格
rows.forEach((row, rowIndexOriginal) => {
let cellIndex = 1; // 逻辑上的单元格索引
let physicalCellIndex = 1; // 实际的Excel单元格索引,考虑到跨列
// 清除已经结束的跨行
if (rowSpans[rowIndexOriginal]) {
rowSpans[rowIndexOriginal] = rowSpans[rowIndexOriginal].filter(span => span.endRow > rowIndex);
}
const cells = row.querySelectorAll('th, td');
cells.forEach(cell => {
// 跳过被跨行单元格覆盖的单元格
while (rowSpans[rowIndexOriginal - 1]?.some(span => span.startCol <= physicalCellIndex && span.endCol >= physicalCellIndex)) {
physicalCellIndex++;
}
const rowSpan = parseInt(cell.getAttribute('rowspan') || 1, 10);
const colSpan = parseInt(cell.getAttribute('colspan') || 1, 10);
worksheet.getCell(rowIndex, physicalCellIndex).value = cell.textContent.trim();
if (rowSpan > 1 || colSpan > 1) {
mergeCellsList.push({ startRow: rowIndex, startCol: physicalCellIndex, endRow: rowIndex + rowSpan - 1, endCol: physicalCellIndex + colSpan - 1 });
// 如果是跨行,则记录下来
if (rowSpan > 1) {
for (let i = 0; i < rowSpan; i++) {
rowSpans[rowIndexOriginal + i] = rowSpans[rowIndexOriginal + i] || [];
rowSpans[rowIndexOriginal + i].push({ startCol: physicalCellIndex, endCol: physicalCellIndex + colSpan - 1, endRow: rowIndex + rowSpan - 1 });
}
}
}
// 更新实际的单元格索引,考虑到跨列
physicalCellIndex += colSpan;
});
rowIndex++;
});
// 合并单元格
mergeCellsList.forEach(mergeInfo => {
worksheet.mergeCells(mergeInfo.startRow, mergeInfo.startCol, mergeInfo.endRow, mergeInfo.endCol);
});
// 导出文件
const buffer = await workbook.xlsx.writeBuffer();
const blob = new Blob([buffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'tableData.xlsx';
a.click();
URL.revokeObjectURL(url);
};
return {
table,
exportToExcel
};
}
};
</script>
<style scoped>
/* 表格整体样式 */
.styled-table {
width: 100%; /* 设置表格宽度为100% */
max-width: 1200px; /* 最大宽度 */
margin: 20px auto; /* 水平居中 */
border-collapse: collapse; /* 边框合并 */
font-family: Arial, sans-serif;
font-size: 16px;
border: 2px solid #007BFF; /* 外边框颜色 */
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); /* 添加阴影效果 */
}
/* 表头样式 */
.styled-table thead th {
background-color: #007BFF; /* 表头背景色 */
color: white;
text-align: center;
padding: 15px;
border: 1px solid #0056b3; /* 表头边框 */
}
/* 表格内容样式 */
.styled-table tbody td {
padding: 12px 15px; /* 单元格内边距 */
text-align: center;
border: 1px solid #ddd; /* 单元格边框 */
}
/* 名字和备注单元格样式 */
.name-cell, .remark-cell {
font-weight: bold; /* 加粗 */
background-color: #f9f9f9; /* 浅灰色背景 */
}
/* 鼠标悬停时的行样式 */
.styled-table tbody tr:hover {
background-color: #f1f1f1; /* 悬停时的背景色 */
}
/* 下载按钮样式 */
button {
display: block;
margin: 20px auto;
padding: 10px 20px;
font-size: 16px;
background-color: #007BFF;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
transition: background-color 0.3s ease;
}
button:hover {
background-color: #0056b3;
}
</style>
-
网页效果
![image]()
-
导出excel效果
![image]()
前端工程师、程序员



浙公网安备 33010602011771号