前言
在我们日常开发中肯定会遇到批量导入
这样的功能实现。
后端:"小凌,你批量导出做的这么优秀,批量导入也做了呗?"。
我:"为啥?这一般都是后端做的呀?"
后端:"你想一下,让用户上传一个文件岂不是要300-400K?如果你前端直接转成JSON数据给我岂不是减少了很多数据传输量?(主要是后端想直接存数据,不用写逻辑)"
秉承着解决问题提升自己
的我决定接下这个任务。
流程图
组件设计
安装依赖
npm install -S xlsx
上传的组件
ExcelImport.vue
<template>
<div class="excelImport">
<input type="file" ref="upload" v-show="false" :accept="accept" />
</div>
</template>
<script>
import XLSX from "xlsx";
export default {
name: "excelImport",
props: {
accept: {
// 允许上传的文件格式
type: String,
default: ".xls,.xlsx",
},
dataRow: {
// 数据开始列 这个注意excel一定要有表头
type: Number,
default: 0,
validator: (val) => {
return val >= 0;
},
},
valueMatch: {
// 数据列 必须与excel中的表列顺序相对应
type: Array,
},
},
data() {
return {};
},
methods: {
cleanUpload() {
// 清空input值
this.$refs.upload.value = null;
},
// 文件上传事件
handleFileChange(event) {
// 这边也可以封装成多个文件上传的形式 目前是单个文件
this.handleReadExcel(event.target.files[0]);
},
// (重点)把文件按照二进制读取
handleReadExcel(file) {
const fileReader = new FileReader();
fileReader.onload = (ev) => {
try {
const fileData = ev.target.result;
const workbook = XLSX.read(fileData, {
type: "binary",
});
const wsname = workbook.SheetNames[0]; // 取第一张表(也可以取多个sheet)
const snArr = XLSX.utils.sheet_to_json(workbook.Sheets[wsname]); // 生成json表格内容
this.excelDataToJson(snArr);
} catch (e) {
console.log(e);
return false;
}
};
fileReader.readAsBinaryString(file);
},
// 表格数据转换
excelDataToJson(snArr) {
let retn = [];
// 如果数据不在第一列 则到相应列去取数据
if (this.dataRow) {
snArr = snArr.slice(this.dataRow, snArr.length);
}
// 如果不用匹配数据则直接返回原始数据
if (!this.valueMatch || this.valueMatch.length === 0) {
// 输出原始数据自己在组件外进行处理
this.$emit("changeExcel", snArr);
}
// 获取一个元素的key值(excel表格原始的key)
let snKeys = Object.keys(snArr[0]);
snArr.forEach((snItem) => {
let pushItem = {};
// 匹配我们传入的新属性
this.valueMatch.forEach((item, index) => {
pushItem[item] = snItem[snKeys[index]];
});
retn.push(pushItem);
});
// 输出匹配后的数据
this.$emit("changeExcel", retn);
},
// 打开上传
open() {
this.$nextTick(() => {
this.$refs.upload.click();
});
},
},
mounted() {
// 绑定更改事件监听
this.$nextTick(() => {
this.$refs.upload.removeEventListener("change", this.handleFileChange);
this.$refs.upload.addEventListener("change", this.handleFileChange);
});
},
beforeDestroy() {
// 移除更改事件监听
this.$refs.upload.removeEventListener("change", this.handleFileChange);
},
};
</script>
使用样例
ExcelImportPage.vue
<template>
<div class="excelImport">
<button @click="toImport">导入Excel</button>
<excel-import
ref="uploadExamFile"
@changeExcel="uploadExamFile"
accept=".xls,.xlsx"
:dataRow="1"
:valueMatch="valueMatch"
></excel-import>
<!-- 展示数据 -->
<table border v-if="dataList && dataList.length > 0">
<!-- 表头 -->
<tr>
<th v-for="hItem in valueTitle" :key="hItem">{{ hItem }}</th>
</tr>
<!-- 数据 -->
<tr v-for="(item, index) in dataList" :key="index">
<td v-for="jItem in valueMatch" :key="jItem">{{ item[jItem] }}</td>
</tr>
</table>
</div>
</template>
<script>
import ExcelImport from "./ExcelImport";
export default {
name: "excelImportPage",
data() {
return {
valueMatch: ["name", "sex", "age", "phone", "department", "position"], // 数据列 必须与excel中的表列顺序相对应
valueTitle: ["姓名", "性别", "年龄", "联系方式", "部门", "职位"],
dataList: [],
};
},
methods: {
// 获取数据
uploadExamFile(data) {
console.log("导出的数据", data);
this.dataList = data;
},
toImport() {
this.$refs.uploadExamFile.open();
},
},
components: {
ExcelImport,
},
};
</script>
使用效果
使用注意
1.表头必须
导入的表格表头必须!导入的表格表头必须!导入的表格表头必须!
表格的第一行必须有,不然数据会少一行
2.dataRow的定义
以下情况下输入参数为0(默认)
以下情况下为1
组件文档
输入参数
参数 | 作用 | 默认值 |
---|---|---|
accept | 控制上传的文件类型 | .xls,.xlsx |
valueMatch | 表列匹配的参数名称如['name','age'] | null |
dataRow | 数据开始行 | 0 |
绑定方法
方法名 | 作用 | 输出参数 |
---|---|---|
changeExcel | excel解析完成后触发 | 解析完成的数据 |
主动触发事件
方法名 | 作用 | 输入参数 |
---|---|---|
open | 打开上传文件 | 无 |
cleanUpload | 清除文件上传的内容 | 无 |
结合业务
用户批量上传带图片的商品信息
我们可以结合之前我们实现的导出功能。
导出文件参考文章:前端导出Excel,让后端刮目相看
1.上传静态资源到OSS。
2.OSS保存静态图片地址列表到后端。
3.导出静态资源列表为Excel。
4.添加商品名称、价格等其他字段。
5.导入商品信息Excel解析成JSON格式。
6.将数据通过接口上传给后端。
项目地址
excel导入组件地址:导入Excel组件数据