前言
项目中的一个批量导入数据的需求,批量导入数据是用的 excel
,需要前端上传 excel
文件时先将文件中的数据解析一下,然后根据业务需求对每一列的字段进行一些基础校验,如字段是否非空,字符串长度是否超出范围等等,接下来就来梳理一下这个需求的基本实现
思路分析
根据需求分析得到批量导入数据使用的 excel
,上传前对 excel
文件中的数据做一些基础校验,可以上传前先将 excel
解析成 json
,得到 json
数据后再根据 json
中的格式,进行按需校验
实战操作
准备导入文件
这里模拟了一个基本的 excel
数据,第一行是表头,下面是表体数据,模拟了三条数据,假设每列数据都是必填
构建上传组件
这里使用 element
的 el-upload
组件,设置组件的 change
事件 :on-change="handleChange"
,使文件发生变化时获取对应的 file
对象
<el-upload class="upload-demo" drag action="https://jsonplaceholder.typicode.com/posts/" :file-list="fileList" :auto-upload="false" :on-change="handleChange" > <i class="el-icon-upload"></i> <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div> <div class="el-upload__tip" slot="tip">只能上传excel文件</div> </el-upload>
获取excel文件内容
通过 handleChange
事件得到 file
对象,根据 FileReader
读取文件内容
handleChange(file) { if (file) { const reader = new FileReader(); reader.onload = (e) => { // 读取 Excel 文件内容 const data = e.target.result; // 处理 Excel 文件内容,获取表格数据 this.processExcelData(data); }; reader.readAsArrayBuffer(file.raw); } }
注意!
reader.readAsArrayBuffer(file.raw);
里面传的参数是file.raw
,file.raw
才是readAsArrayBuffer
需要的blob
对象
处理excel获取json数据
这里使用 processExcelData()
函数解析 excel
表格数据,解析表格数据使用 xlsx
库,解析 excel
文件数据这里分为以下几个步骤
- 使用
String.fromCharCode.apply(null, new Uint8Array(data))
得到文件二进制字符串 - 使用
XLSX.read(binaryString, { type: "binary" })
将二进制字符串转成workbook
对象 - 通过
worksheet
获取worksheet
- 使用
XLSX.utils.sheet_to_json(worksheet, { header: 1 });
将worksheet
转为json
对象 - 得到的
json
对象后进行数据解析,从第二行开始验证数据,判断每一行的每列数据是否为空,如果有数据,则进下一步,如果为空,则打印错误日志(需求场景中是如果出现校验错误应该限制上传操作)
processExcelData(data) { const binaryString = String.fromCharCode.apply( null, new Uint8Array(data) ); // 将二进制字符串转为workbook const workbook = XLSX.read(binaryString, { type: "binary" }); // 获取第一个sheet const sheetName = workbook.SheetNames[0]; const worksheet = workbook.Sheets[sheetName]; // 将sheet转为json对象· const jsonData = XLSX.utils.sheet_to_json(worksheet, { header: 1 }); // 获取表头 const titleList = jsonData[0]; jsonData.forEach((item, index) => { if (index > 0) { for (let i = 0; i < titleList.length; i++) { if (item[i]) { } else { console.error("第 " + (index + 1) + " 行的第 " + (i + 1) + " 列 " + titleList[i] + " 为空"); } } } }); },
到这里整个需求的最核心的部分在 Demo
中都已经实现了,剩下的就是业务场景中按需调整部分代码逻辑就行了
提示!
- 这里面的获取
sheet
时要基于实际业务情况,Demo
中默认是只有一个sheet
Demo
中的表头数据默认也是只有第一行
演示效果
简单说明一下这里面的操作逻辑,页面刷新后,打开控制台,选择 test.xlsx
文件,文件变化后查看控制台解析校验结果
技术栈
- vue: 2.6.14
- element ui: 2.15.14
- xlsx: 0.17.0
Demo地址
完整代码
Excel测试文件
写在最后
关于这种比较通用的文件上传或者文件解析功能,在项目里适合基于业务封装成通用的组件或函数,在未来类似的需求中可以相对快速完成相关功能
关于文件解析校验,还有更优雅的实现思路吗?