前言
我们在做业务需求的时候,会遇到展示表格的页面,如果只有一个表格,我们可以直接把内容填充到我们的代码中,有时候业务需要不同的分类展示不同的表格,而表格内容是静态的,这类需求,我之前的处理是写个本地json文件,每次新增让产品直接把数据录到json文件中。有时候业务会把Excel表格发给我,我自己进行录入。闲暇的时候我在想,可否通过解析Excel文件直接拿到内容呢?
于是我进行了后面的尝试。
Excel文件的读取
目标功能
我想实现的功能主要有几部分:读取Excel文件,识别多个工作表,每个工作表按行将数据放入数组中。最终解析输入如下:
Excel文件数据
两个工作表:鞋子和裤子
读取的完整数据
{ "fileName": "测试读取.xlsx", "list": [ { "sheetName": "鞋子", "list": [ { "goodName": "鞋子A版", "size": "37", "color": "白色" }, { "goodName": "鞋子B版", "size": "38", "color": "米色" }, { "goodName": "鞋子C版", "size": "38", "color": "黑色" } ] }, { "sheetName": "裤子", "list": [ { "goodName": "裤子A版", "size": "S", "color": "白色" }, { "goodName": "裤子B版", "size": "M", "color": "黑色" }, { "goodName": "裤子C版", "size": "L", "color": "红色" }, { "goodName": "裤子D版", "size": "XL", "color": "紫色" } ] } ] }
下面我将功能进行细分。
读取Excel文件
解析插件
插件:xlsx.core.min.js
读取方法
FileReader可以读取Excel文件内容,它的详细知识点可以查看MDN
我这里使用的FileReader.readAsBinaryString(file) :开始读取指定的Blob中的内容。一旦完成,result属性中将包含所读取文件的原始二进制数据。
HTML部分
包括文件上传和数据内容展示两部分,其中文件上传有限制文件类型必须是.xls或.xlsx后缀的。
<!DOCTYPEhtml><html><head><title>读取excel文件解析内容</title><scriptsrc="https://cdn.bootcss.com/xlsx/0.11.5/xlsx.core.min.js"></script><style> .warp { width: 100%; display: flex; justify-content: flex-start; margin-top: 10px; } span { display: block; } textarea { width: 80%; display: block; } .file { margin-bottom: 15px; } .tip { margin-bottom: 15px; } </style></head><body><h3class="tip">目前只能解析简单的纵向列表数据,支持多个工作表</h3><divclass="file"><inputtype="file"accept=".xls,.xlsx"onchange="uploadFile(this)"id="myFile"/></div><divclass="warp"><span>内容展示:</span><textareaid="content"rows="30"></textarea></div></body></html>
上传操作方法
先判断上传文件是否为空,如果不为空才进行下一步。
/** * 文件上传操作 * @param {Element} obj 选择的文件元素 * @return {void} 无 */functionuploadFile(obj) { //导入if (!obj.files) { return; } letf=obj.files[0]; readExcelFile(obj, f); }
文件读取
XLSX为sheetjs插件提供的方法
- XLSX.read(data, read_opts):尝试解析data;
- workbook.SheetNames 是工作簿中工作表的有序列表;
- wb.Sheets[sheetname] 返回一个代表工作表的对象;
- XLSX.utils.sheet_to_json生成不同类型的 JS 对象。
/** @name 读取完成的数据 */varjsonContent; /** * Excel文件处理方法 * @param {Element} obj 选择的文件元素 * @param {File} f 文件对象 * @return {void} 无 */functionreadExcelFile(obj, f) { varreader=newFileReader(); reader.onload=function (e) { vardata=e.target.result; jsonContent=XLSX.read(data, { type: 'binary', }); /** @name 工作簿中工作表的有序列表 */constsheetNamesList=jsonContent.SheetNames; constsheetsList= []; sheetNamesList.map(sheetItem=> { //jsonContent.Sheets[Sheet名]获取该Sheet的数据constsheetItemData=jsonContent.Sheets[sheetItem]; sheetsList.push({ sheetName: sheetItem, list: XLSX.utils.sheet_to_json(sheetItemData), // 数据转成json格式 }); }); pageShow(sheetsList, f); }; reader.readAsBinaryString(f); }
重组Excel文件数据
- 现在的数据key为工作表表头的值,是中文名称,可以根据定义的变量名进行数据重组,所以我加了一个变量枚举renameObj。注:如果多个工作表的表头不一致,可重置renameObj对象,并改造resetTableData方法内的代码即可;
- resetTableData方法会将数据的所有key替换成枚举中的变量值;
- 变量arrayData为最终的处理之后的Excel数据,这时已经将Excel文件中的数据处理成了方便前端在页面回显的数据。
/** * 重组key-value * @param {Array} list 需要操作的数组 * @param {Object} renameObj 重命名变量对象 * @return {Array} 合并成的新数组 */functionresetTableData(list, renameObj) { letnewList= [].concat(list); newList.map(item=> { for (letkinitem) { constrenameKey=renameObj[k]; item[renameKey] =item[k]; deleteitem[k]; } }); returnnewList; // 最终输出} /** * 数据回显 * @param {Array} list 数据数组对象 * @param {File} f 文件对象 * @return {void} 无 */functionpageShow(list, f) { letjsonData=''; /** @name 列表展示的变量名枚举 */constrenameObj= { 商品名: 'goodName', 大小: 'size', 颜色: 'color', }; letnewList= [].concat(list); newList.map(item=> { item.list=resetTableData(item.list, renameObj); }); /** @name 最终的数据 */letarrayData= { fileName: f.name, list: [].concat(newList), }; constcontent=document.getElementById('content'); jsonData=JSON.stringify(arrayData, null, 4); content.innerHTML=jsonData; }
浏览器展示
完整代码
<!DOCTYPEhtml><html><head><title>读取excel文件解析内容</title><scriptsrc="https://cdn.bootcss.com/xlsx/0.11.5/xlsx.core.min.js"></script><style> .warp { width: 100%; display: flex; justify-content: flex-start; margin-top: 10px; } span { display: block; } textarea { width: 80%; display: block; } .file { margin-bottom: 15px; } .tip { margin-bottom: 15px; } </style></head><body><h3class="tip">目前只能解析简单的纵向列表数据,支持多个工作表</h3><divclass="file"><inputtype="file"accept=".xls,.xlsx"onchange="uploadFile(this)"id="myFile"/></div><divclass="warp"><span>内容展示:</span><textareaid="content"rows="30"></textarea></div></body><scripttype="text/javascript">/** *FileReader读取方法:readAsBinaryString(file):开始读取指定的Blob中的内容。一旦完成,result属性中将包含所读取文件的原始二进制数据。 *@return {void} 无 **//** @name 读取完成的数据 */varjsonContent; /** * 文件上传操作 * @param {Element} obj 选择的文件元素 * @return {void} 无 */functionuploadFile(obj) { //导入if (!obj.files) { return; } letf=obj.files[0]; readExcelFile(obj, f); } /** * Excel文件处理方法 * @param {Element} obj 选择的文件元素 * @param {File} f 文件对象 * @return {void} 无 */functionreadExcelFile(obj, f) { varreader=newFileReader(); reader.onload=function (e) { vardata=e.target.result; jsonContent=XLSX.read(data, { type: 'binary', }); /** @name 工作簿中工作表的有序列表 */constsheetNamesList=jsonContent.SheetNames; constsheetsList= []; sheetNamesList.map(sheetItem=> { //jsonContent.Sheets[Sheet名]获取该Sheet的数据constsheetItemData=jsonContent.Sheets[sheetItem]; sheetsList.push({ sheetName: sheetItem, list: XLSX.utils.sheet_to_json(sheetItemData), // 数据转成json格式 }); }); pageShow(sheetsList, f); }; reader.readAsBinaryString(f); } /** * 重组key-value * @param {Array} list 需要操作的数组 * @param {Object} renameObj 重命名变量对象 * @return {Array} 合并成的新数组 */functionresetTableData(list, renameObj) { letnewList= [].concat(list); newList.map(item=> { for (letkinitem) { constrenameKey=renameObj[k]; item[renameKey] =item[k]; deleteitem[k]; } }); returnnewList; // 最终输出 } /** * 数据回显 * @param {Array} list 数据数组对象 * @param {File} f 文件对象 * @return {void} 无 */functionpageShow(list, f) { letjsonData=''; /** @name 列表展示的变量名枚举 */constrenameObj= { 商品名: 'goodName', 大小: 'size', 颜色: 'color', }; letnewList= [].concat(list); newList.map(item=> { item.list=resetTableData(item.list, renameObj); }); /** @name 最终的数据 */letarrayData= { fileName: f.name, list: [].concat(newList), }; constcontent=document.getElementById('content'); jsonData=JSON.stringify(arrayData, null, 4); content.innerHTML=jsonData; } </script></html>
总结
日常开发中,如果觉得哪些不方便、不顺手的,不妨写个小工具协助开发,避免简单的重复的工作占用我们过多的时间。