需求说明
1.需要前端做数据导出(非调用接口)
2.需要对上传的表格数据做验证,不通过验证需要提示格式不正确,阻拦上传
技术栈介绍
React
+Antdesign
+XLSX
js-xlsx 介绍
由SheetJS
出品的js-xlsx
是一款非常方便的只需要纯JS即可读取和导出excel的工具库,功能强大,支持格式众多,支持xls、xlsx、ods(一种OpenOffice专有表格文件格式)等十几种格式。
GitHub地址:https://github.com/SheetJS/sheetjs
官网地址:https://sheetjs.com/
React使用文档:https://docs.sheetjs.com/docs/demos/frontend/react
导出的简单使用
首先插件的几个重要的名词对应如下图
根据数据类型,写法可分为
-
纯数组
/** * 导出 excel 文件 * @param array JSON 数组 * @param sheetName 第一张表名 * @param fileName 文件名 */ export function exportExcelFile(array: any[], sheetName = '表1', fileName = 'example.xlsx') { const jsonWorkSheet = xlsx.utils.json_to_sheet(array); const workBook: WorkBook = { SheetNames: [sheetName], Sheets: { [sheetName]: jsonWorkSheet, } }; return xlsx.writeFile(workBook, fileName); }
-
对象数组(后端返回的数组是一堆对象)(第一行为中文表头)
export function exportExcelFile(array: any[], sheetName = '表1', fileName = 'example.xlsx') { // 属性名数组 const header = ['name', 'age', 'addr']; // 最终数组 第一行为中文表头 let finalData = [ { name: '账号', age: '密码', addr: '地址', }, ]; array?.forEach((item) => { const pickedItem = item?.map((e) => pick(e, header)); // 此方法是loadash中,找到当前对象e中,对应header属性名称的属性,返回一个对象 if (pickedItem) { finalData.push(...pickedItem); } }); const jsonWorkSheet = xlsx.utils.json_to_sheet(finalData,header); const workBook: WorkBook = { SheetNames: [sheetName], Sheets: { [sheetName]: jsonWorkSheet, } }; return xlsx.writeFile(workBook, fileName); }
导入的简单使用
-
简单导入,获取表格数据
/** * 从 excel 文件读取数据 * @param excelRcFileBuffer excel 文件 */ export function importExcelFromBuffer<Item = any>(excelRcFileBuffer: ArrayBuffer): Item[] { // 读取表格对象 const workbook = xlsx.read(excelRcFileBuffer, {type: 'buffer'}); // 找到第一张表 const sheetNames = workbook.SheetNames; const sheet1 = workbook.Sheets[sheetNames[0]]; // 读取内容 return xlsx.utils.sheet_to_json(sheet1); }
-
结合业务场景,需要对上传数据做校验,此
demo
简单校验是否为中文和是否为数字// 此处的onChange方法为 Antd的Upload组件的API onChange(info) { // 文件状态为done时,可获取完整文件流 if (info.file.status === 'done') { const fileReader = new FileReader(); // 是否成功的标识 let canPass = true; fileReader.onload = (e) => { const data = e.target.result; // 将获取的文件流 以数组形式读取 const workBook = XLSX.read(data, { type: 'array' }); // 获取当前文件第一个表的表名 const workSheetNames = workBook.SheetNames[0]; // 拿到对应的表 const workSheet = workBook.Sheets[workSheetNames]; // 通过需要的数据属性,把数据整理成对象数组 const excelData = XLSX.utils.sheet_to_json(workSheet, { header: Object.keys(['name','age','addr']), raw: false, }); // 删除第一行中文表头 excelData.shift(); // 如果上传的空数据就 不通过 if (!(excelData && excelData.length > 0)) { canPass = false; }else{ // name不允许有中文,age需要是数字 const noPass= excelData.find(e=>hasChinese(e.name)||!isNumber(e.age)) if(noPass){ canPass = false; } } if (canPass) { const fileName = info.file.name; // 成功的回调(自定义的) onSuccess(excelData, fileName); message.success(`${fileName} 上传成功`); } else { message.warning('请按照格式填写'); } }; } else if (info.file.status === 'error') { message.error(`${info.file.name} 上传失败`); } } //**************单独方法 // 判断是否含有汉字 export const hasChinese = (str) => { const reg = /[\u4E00-\u9FA5]/g; return reg.test(str); }; // 判断是否为数字 export const isNumber = (str) => { const reg = /^(-?\d+)(\.\d+)?$/; return reg.test(str); };
有个博主讲了更多业务场景可查看:https://www.jianshu.com/p/f9ba3dd3cd4f