Vue3 实现 Excel 文件导入导出功能详解
本文基于 Element Plus + xlsx 库实现一个支持 Excel 文件导入导出的 Vue3 组件,适合用于教学场景演示前后端交互之外的纯前端文件处理方案。
一、功能概述
该组件实现了以下核心功能:
- Excel 文件导入:通过文件选择器加载
.xlsx/.xls
格式文件 - 数据动态渲染:将 Excel 表格内容实时展示在 Vue 响应式表格中
- 数据格式转换:自动完成 Sheet 数据与 JSON 对象的双向转换
- Excel 文件导出:将当前表格数据导出为标准 Excel 文件
二、技术栈依赖
- Vue3 (Composition API 模式)
- Element Plus (UI 组件库)
- SheetJS xlsx (Excel 处理库)
需通过 npm 安装依赖:
npm install xlsx element-plus
三、核心代码解析
1. 模板结构 (template 部分)
<template>
<!-- 导入组件 -->
<el-upload
class="upload-demo"
action=""
:auto-upload="false" # 禁用自动上传
:show-file-list="false" # 隐藏文件列表
:on-change="handleImport" # 文件选择回调
accept=".xlsx, .xls" # 限制文件类型
>
<el-button type="primary">导入Excel</el-button>
</el-upload>
<!-- 导出按钮 -->
<el-button type="primary" @click="exportExcel">导出</el-button>
<!-- 数据表格 -->
<el-table :data="tableData" border style="width: 70vw">
<!-- 列定义由 handleImport 动态生成 -->
</el-table>
</template>
2. 脚本逻辑 (script setup 部分)
响应式数据定义
import { ref } from "vue";
import { read, writeFileXLSX, utils } from "xlsx"; // xlsx 核心方法
const tableHeaders = ref([]); // 存储表头信息
const tableData = ref([...]); // 存储表格数据
文件导入处理
const handleImport = (file) => {
// 文件类型校验
if(!/\.xlsx|\.xls$/.test(file.name)) {
ElMessage.error("仅支持 Excel 文件");
return;
}
const reader = new FileReader();
reader.onload = (e) => {
try {
// 读取文件内容
const data = new Uint8Array(e.target.result);
const workbook = read(data, { type: "array" });
// 解析第一个工作表
const firstSheetName = workbook.SheetNames[0];
const worksheet = workbook.Sheets[firstSheetName];
// 转换为二维数组 [[表头], [行数据]...]
const jsonData = utils.sheet_to_json(worksheet, { header: 1 });
// 提取表头
tableHeaders.value = jsonData[0];
// 构造对象数组
tableData.value = jsonData.slice(1).map(row => {
return tableHeaders.value.reduce((obj, header, index) => {
obj[header] = row[index] || "";
return obj;
}, {});
});
ElMessage.success("导入成功");
} catch (error) {
ElMessage.error(`解析失败: ${error.message}`);
}
};
// 以 ArrayBuffer 格式读取文件
reader.readAsArrayBuffer(file.raw);
};
文件导出处理
const exportExcel = () => {
// 将对象数组转为工作表
const worksheet = utils.json_to_sheet(tableData.value);
// 创建工作簿并添加工作表
const workbook = utils.book_new();
utils.book_append_sheet(workbook, worksheet, "Sheet1");
// 触发文件下载
writeFileXLSX(workbook, "data.xlsx");
};
四、关键技术点解析
1. 文件读取原理
- 使用
FileReader
的readAsArrayBuffer
方法读取二进制数据 - 通过
Uint8Array
类型数组保证二进制数据完整性 - xlsx 库支持多种解析模式(array/binary/base64)
2. 数据转换机制
转换方向 | 方法 | 特点 |
---|---|---|
Excel → JSON | sheet_to_json(sheet, {header:1}) | header=1 返回二维数组 |
JSON → Excel | json_to_sheet(json) | 需要标准对象数组 |
**
3. 性能优化建议
- 大文件处理:添加 loading 状态提示
- 错误处理:增强异常捕获和用户反馈
- 类型映射:自定义日期等特殊格式处理
五、完整代码
<template>
<div>
<el-upload
class="upload-demo"
action=""
:auto-upload="false"
:show-file-list="false"
:on-change="handleImport"
accept=".xlsx, .xls"
>
<el-button type="primary">导入Excel文件</el-button>
</el-upload>
</div>
<el-button type="primary" @click="exportExcel">导出</el-button>
<el-table :data="tableData" border style="width: 70vw">
<el-table-column prop="date" label="Date" width="180" />
<el-table-column prop="name" label="Name" width="180" />
<el-table-column prop="address" label="Address" />
</el-table>
</template>
<script setup>
import { ref } from "vue";
import { read, writeFileXLSX, utils } from "xlsx";
import { ElMessage } from "element-plus";
const tableHeaders = ref([]);
const tableData = ref([
{
date: "2016-05-03",
name: "Tom",
address: "No. 189, Grove St, Los Angeles",
},
{
date: "2016-05-02",
name: "Tom",
address: "No. 189, Grove St, Los Angeles",
},
{
date: "2016-05-04",
name: "Tom",
address: "No. 189, Grove St, Los Angeles",
},
{
date: "2016-05-01",
name: "Tom",
address: "No. 189, Grove St, Los Angeles",
},
]);
// 处理文件导入
const handleImport = (file) => {
// 检查文件类型
const isExcel = /\.(xlsx|xls)$/.test(file.name);
if (!isExcel) {
ElMessage.error("只能上传Excel文件!");
return;
}
const reader = new FileReader();
reader.onload = (e) => {
try {
const data = new Uint8Array(e.target.result);
const workbook = read(data, { type: "array" });
const firstSheetName = workbook.SheetNames[0];
const worksheet = workbook.Sheets[firstSheetName];
// 转换JSON数据
const jsonData = utils.sheet_to_json(worksheet, { header: 1 });
// 处理表头
tableHeaders.value = jsonData[0];
// 处理表格内容(跳过表头)
tableData.value = jsonData.slice(1).map((row) => {
return tableHeaders.value.reduce((obj, header, index) => {
obj[header] = row[index] || "";
return obj;
}, {});
});
ElMessage.success("文件导入成功");
} catch (error) {
ElMessage.error("文件解析失败: " + error.message);
}
};
reader.readAsArrayBuffer(file.raw);
};
const exportExcel = () => {
const worksheet = utils.json_to_sheet(tableData.value);
const workbook = utils.book_new();
utils.book_append_sheet(workbook, worksheet, "Sheet1");
writeFileXLSX(workbook, "data.xlsx");
};
</script>
六、扩展应用场景
- 添加多 sheet 支持
- 实现列名映射配置
- 结合 axios 实现服务端文件处理
- 添加数据校验和清洗功能