在Vue 2中导入Excel数据并将其回显在页面上,需要使用 XLSX 库, 这个库可以用来解析 Excel文件。首先先下载 XLSX 库依赖,其次封装上传Excel的组件,最后在父组件中使用子组件。
关于 XLSX 的详细介绍移步:https://www.cnblogs.com/ajaemp/p/12880847.html
准备工作就绪,需要在父组件上添加一个按钮触发文件上传的弹框打开或关闭。
<!-- 触发批量弹出框按钮 -->
<div>
<el-button type="primary" size="mini" @click="showImportDataDialog">批量导入</el-button>
</div>
在data中定义变量uploadVisible 的值为 false, 然后在 methods 中定义 showImportDataDialog 方法。
// 显示缺失项批量上传窗口
showImportDataDialog() {
this.uploadVisible = true
},
-
安装 XLSX 库
npm install xlsx
-
封装上传Excel的组件
这里我将上传附件的组件视为公共组件,所以在 src/components 目录下新建了一个 FileUpload 目录,在该目录下新建 XXX.vue 组件。该组件的主要作用就是父组件点击批量导入按钮时,打开一个对话框,可以下载导入模板,并且支持拉拽的方式上传Excel数据,然后将读取到的Excel数据以集合的方式返回给父组件。通过$emit () 触发父组件的事件。

<!-- 读取Excel数据在前端页面回显 --->
<template>
<!-- 上传弹窗对话框, 模板数据导入 -->
<el-dialog
:title="dialogTitle"
:modal="false"
append-to-body
:visible.sync="dialogVisible"
width="500px"
@close="closeDialog">
<el-row>
无模板?点击
<el-button size="medium" type="text" @click="downFile">模板下载</el-button>
</el-row>
<!-- Element UI 上传组件 -->
<el-upload
class="upload-demo"
ref="upload"
drag
action
:limit="1"
:file-list="fileList"
:auto-upload="false"
:before-upload="beforeUpload"
:on-change="handleFileChange"
:extra-params="extraParams"
:dialog-title="dialogTitle">
<!-- :http-request="uploadHttpRequest" -->
<i class="el-icon-upload"></i>
<div class="el-upload__text">
将文件拖到此处,或<em>点击上传</em>
</div>
</el-upload>
<!-- 弹窗底部按钮 -->
<span slot="footer" class="dialog-footer">
<el-button type="primary" size="mini" @click="uploadMultipleFiles" :loading="uploading">{{ uploading ? '上传中...' : '开始上传' }}</el-button>
<!-- <el-button type="primary" size="mini" @click="submitUpload()" :loading="uploading">{{ uploading ? '上传中...' : '开始上传' }}</el-button> -->
<el-button size="mini" @click="cancelUpload">取 消</el-button>
</span>
</el-dialog>
</template>
<script>
import * as XLSX from 'xlsx';
import { reqFileUpload, reqDownTemplate } from '@/api/common.js'
import { resolve } from 'core-js/fn/promise';
export default {
name: 'ShowImportData',
props: {
// 控制弹窗显示/隐藏
visible: {
type: Boolean,
default: false
},
// 上传类型,用于区分不同业务
dialogTitle: {
type: String,
default: '导入数据'
},
// 模板名称
tempFileName: {
type: String,
default: '导入数据模板'
},
// 额外的参数
extraParams: {
Type: Object,
default: () => ({})
},
},
data() {
return {
dialogVisible: this.visible, // 弹窗显示状态
fileList: [], // 文件
uploading: false, // 上传状态
};
},
watch: {
// 监听visible变化,同步到dialogVisible
visible(newVal) {
this.dialogVisible = newVal;
},
// 监听dialogVisible变化,通知父组件
dialogVisible(newVal) {
this.$emit('update:visible', newVal);
}
},
methods: {
handleFileChange(file, fileList) {
// 保存所有原始文件对象
this.fileList = fileList.map(f => f.raw);
},
// 上传文件之前的钩子:判断上传文件格式、大小等,若返回false则停止上传
beforeUpload(file) {
// 文件类型
const isType = file.type === "application/vnd.ms-excel";
const isTypeComputer =
file.type ===
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
const fileType = isType || isTypeComputer;
if (!fileType) {
this.$message.error("上传文件只能是xls/xlsx格式!");
}
// 文件大小限制为10M
/* const fileLimit = file.size / 1024 / 1024 < 10;
if (!fileLimit) {
this.$message.error("上传文件大小不超过10M!");
}
return fileType && fileLimit; */
return fileType;
},
async uploadMultipleFiles() {
if (this.fileList.length == 0) {
this.$message.warning('请选择文件')
return false;
}
this.uploading = true; // 显示按钮加载中
try {
//得到文件
const file = this.fileList[0]
const jsonData = await this.readExcelFile(file) // 调用excel处理方法
if (!jsonData || jsonData.length === 0) {
this.$message.warning('Excel文件中没有数据');
return;
}
// 通过事件向父组件传递数据
this.$emit('import-success', jsonData);
this.$message.success(`成功导入 ${jsonData.length} 条数据`);
// 清空文件列表
this.fileList = [];
// this.$refs.upload.clearFiles()
} catch(error) {
console.error('导入失败:', error);
this.$message.error('导入失败:' + error.message);
this.$emit('import-error', error);
} finally {
this.uploading = false; // 显示按钮立即上传
}
},
// excel 处理
readExcelFile(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsArrayBuffer(file); // 一次性将整个 Excel 文件读取到内存中
reader.onload = (e) => {
try {
const data = new Uint8Array(reader.result);
const workbook = XLSX.read(data, { type: 'array' });
// 因为excle分很多页数,找到你对应的那一页
// 假设我们只读取第一个工作表
const firstSheetName = workbook.SheetNames[0];
const worksheet = workbook.Sheets[firstSheetName];
// 将工作表转换为JSON数组并赋值
const jsonData = XLSX.utils.sheet_to_json(worksheet);
// console.log('解析后的数据:', jsonData);
resolve(jsonData);
} catch(error) {
reject(new Error('解析Excel失败:' + error.message));
}
};
}
)},
// // 自定义上传方法,param是默认参数,可以取得file文件信息,具体信息如下图
// async uploadHttpRequest(param) {
// console.log(1)
// console.log(param.file)
// this.uploading = true; // 显示按钮加载中
// // FormData对象,添加参数只能通过append('key', value)的形式添加
// const formData = new FormData();
// // 添加文件对象
// formData.append("file", param.file);
// /*const config = {
// headers: {
// "Content-Type": "multipart/form-data"
// }
// };*/
// console.log(param.file)
// // const res = await reqFileUpload(this.uploadUrl, formData);
// // if (res.code == 200) {
// // this.$emit("closeUpload");
// // this.uploading = false;
// // this.$message.success(res.message);
// // } else {
// // this.$refs.upload.clearFiles(); // 清除上传文件对象
// // this.fileList = []; // 清空选择的文件列表
// // this.uploading = false;
// // this.$message.error(res.message)
// // }
// },
// 上传至服务器
submitUpload() {
this.$refs.upload.submit();
},
cancelUpload() {
this.uploading = false; // 按钮重置
this.$refs.upload.clearFiles(); // 清除上传文件对象
this.fileList = []; // 清空选择的文件列表
this.$emit("close-upload");
},
closeDialog() {
this.$refs.upload.clearFiles(); // 清除上传文件对象
this.fileList = []; // 清空选择的文件列表
this.$emit('close-upload');
},
// 下载模板
async downFile() {
try {
const response = await reqDownTemplate(this.tempFileName);
// 创建 Blob URL
const blobUrl = URL.createObjectURL(response);
// 创建下载链接并触发下载
const link = document.createElement('a');
link.href = blobUrl;
link.download = this.tempFileName;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
// 释放 Blob URL 内存
URL.revokeObjectURL(blobUrl);
} catch (error) {
console.log(error)
}
},
}
};
</script>
<style scoped>
.upload-demo {
text-align: center;
}
.el-upload-dragger {
width: 100%;
}
</style>
- 父组件使用子组件
在父组件中引入子组件,然后注册该组件,之后就可以使用该组件。
在script 块内引入子组件
import ShowImportData from '@/components/FileUpload/showImportData.vue' // 读取excel数据并返回
注册组件
components: {
ShowImportData
},
在父组件中使用组件
其中closeUpload (关闭上传附件弹出框)、 importError (读取失败时触发父组件的方法)、importSuccess (读取失败时触发父组件的方法)都是子组件触发父组件的执行方法。
<!-- 批量导入上传组件 -->
<show-import-data
:visible.sync="uploadVisible"
:temp-file-name="templateFileName"
:accept="'.xlsx,.xls'"
@close-upload="closeUpload"
@import-error="importError"
@import-success="importSuccess"/>
在methods 中的方法
// 关闭上传组件弹框
closeUpload() {
this.uploadVisible = false
},
// 处理子组件触发的导入数据成功败的函数
importSuccess(data) {
// 关闭上传弹窗
this.closeUpload()
// 生成数据行并赋值,通过excel表头数据读取该列单元格的值
data.forEach(item => {
this.correctionForm.rowList.push({
rowIndex: this.nextId++,
state: item.状态, // 状态
fileList: [], // 附件列表
})
})
},
// 处理子组件触发的导入数据失败的函数
importError(error) {
this.$message.error(error.message || '导入失败');
this.closeUpload()
},