React读取Excel——js-xlsx 插件的使用
介绍
SheetJS js-xlsx 是一款能够读写多种格式表格的插件,浏览器支持良好,并且能在多个语言平台上使用,目前在 github 上有 12602 个 star,
刚好项目中遇到了前端解析 excel 的需求,所以就尝试使用了一下,这里将使用方法和遇到的问题简单记录一下。
插件地址:https://github.com/SheetJS/js-xlsx
使用
1. 安装依赖
进入项目文件夹,安装 xlsx
npm install xlsx
2. 在项目中引入
import * as XLSX from \'xlsx\';
3. 定义上传 input
<input type=\'file\' accept=\'.xlsx, .xls\' onChange={this.onImportExcel} />
4. 定义获取和解析 excel 对象的方法
onImportExcel = file => { // 获取上传的文件对象 const { files } = file.target; // 通过FileReader对象读取文件 const fileReader = new FileReader(); fileReader.onload = event => { try { const { result } = event.target; // 以二进制流方式读取得到整份excel表格对象 const workbook = XLSX.read(result, { type: \'binary\' }); let data = []; // 存储获取到的数据 // 遍历每张工作表进行读取(这里默认只读取第一张表) for (const sheet in workbook.Sheets) { if (workbook.Sheets.hasOwnProperty(sheet)) { // 利用 sheet_to_json 方法将 excel 转成 json 数据 data = data.concat(XLSX.utils.sheet_to_json(workbook.Sheets[sheet])); // break; // 如果只取第一张表,就取消注释这行 } } console.log(data); } catch (e) { // 这里可以抛出文件类型错误不正确的相关提示 console.log(\'文件类型不正确\'); return; } }; // 以二进制方式打开文件 fileReader.readAsBinaryString(files[0]); }
定义方法后在浏览器中报了如下错误:
Failed to compile
./node_modules/xlsx/dist/cpexcel.js
Module not found: Can\'t resolve \'./cptable\' in \'/Users/wangxi/Desktop/Code/admin/node_modules/xlsx/dist\'
大意是说在 cpexcel.js 文件中找不到 ./captable 模块,于是在 github 上的 issue 中输入问题,发现问题还是挺普遍的,官方给出的解决方案如下:
即在 webpack 配置文件中添加如下 external 配置:
externals: [ { \'./cptable\': \'var cptable\', \'../xlsx.js\': \'var _XLSX\' } ]
保存并重新编译,浏览器又抛出如下错误:
The externals config must be Plain Object or Function, but got [object Object]
“externals 配置项必须为纯对象或函数,但是却得到了对象形式的数组”,所以原因是 externals 的格式不对:
externals 配置支持三种形式,分别是 Array、Object 和 Reg,上述的配置项内容是一个对象,所以应该为用 Object 形式,所以只要把外面的中括号去掉就可以了:
externals: { \'./cptable\': \'var cptable\', \'../xlsx.js\': \'var _XLSX\' }
更多关于 webpack externals 配置的学习,可以参考:【webpack externals 深入理解】
测试
运行代码,在浏览器中打开页面显示如下:
点击 Choose File,在本地选择一个内容如下的 excel 文件:
点击确定,上传后在浏览器控制台查看打印信息:
可以发现,excel 已经读取成功并且转换成了 json 格式的数据,之后就可以对 json 数据进行分析和处理啦。
完善
1. 使用原生 input 标签显示效果比较粗糙,因为对组件简单地进行了样式上的美化,效果如下:
2. 针对文件上传和读取结果分别做了对应的提示(这里使用 ant design 中的 message 组件)
demo 完整代码如下:
// excel.js import React, { Component } from \'react\'; import { Button, Icon, message } from \'antd\'; import * as XLSX from \'xlsx\'; import styles from \'./index.less\'; class Excel extends Component { onImportExcel = file => { // 获取上传的文件对象 const { files } = file.target; // 通过FileReader对象读取文件 const fileReader = new FileReader(); fileReader.onload = event => { try { const { result } = event.target; // 以二进制流方式读取得到整份excel表格对象 const workbook = XLSX.read(result, { type: \'binary\' }); // 存储获取到的数据 let data = []; // 遍历每张工作表进行读取(这里默认只读取第一张表) for (const sheet in workbook.Sheets) { // esline-disable-next-line if (workbook.Sheets.hasOwnProperty(sheet)) { // 利用 sheet_to_json 方法将 excel 转成 json 数据 data = data.concat(XLSX.utils.sheet_to_json(workbook.Sheets[sheet])); // break; // 如果只取第一张表,就取消注释这行 } } // 最终获取到并且格式化后的 json 数据 message.success(\'上传成功!\') console.log(data); } catch (e) { // 这里可以抛出文件类型错误不正确的相关提示 message.error(\'文件类型不正确!\'); } }; // 以二进制方式打开文件 fileReader.readAsBinaryString(files[0]); } render() { return ( <div style={{ marginTop: 100 }}> <Button className={styles[\'upload-wrap\']}> <Icon type=\'upload\' /> <input className={styles[\'file-uploader\']} type=\'file\' accept=\'.xlsx, .xls\' onChange={this.onImportExcel} /> <span className={styles[\'upload-text\']}>上传文件</span> </Button> <p className={styles[\'upload-tip\']}>支持 .xlsx、.xls 格式的文件</p> </div > ); } } export default Excel;
// index.less .upload-wrap { display: inline-block; position: relative; width: 124px; padding: 3px 5px; overflow: hidden; } .file-uploader { position: absolute; width: 100%; height: 100%; top: 0; left: 0; outline: none; opacity: 0; background-color: transparent; } .upload-text { display: inline-block; margin-left: 5px; } .upload-tip { display: inline-block; margin-left: 10px; color: #999; }
【参考】