SheetJS js-xlsx 是一款可以讀寫多種格式表格的插件,瀏覽器支持良好,而且能在多個語言平臺上使用,目前在 github 上有 12602 個 star,前端
恰好項目中遇到了前端解析 excel 的需求,因此就嘗試使用了一下,這裏將使用方法和遇到的問題簡單記錄一下。node
插件地址: GitHub地址react
進入項目文件夾,安裝 xlsxwebpack
npm install xlsx
複製代碼
import * as XLSX from 'xlsx';
複製代碼
<input type='file' accept='.xlsx, .xls' onChange={this.onImportExcel} />
複製代碼
accept 屬性定義了上傳文件支持的類型,onChange 操做中的 importExcel 方法定義了上傳文件時執行的操做。git
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]);
}
複製代碼
定義方法後在瀏覽器中報了以下錯誤: github
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 配置:web
externals: [
{
'./cptable': 'var cptable',
'../xlsx.js': 'var _XLSX'
}
]
複製代碼
保存並從新編譯,瀏覽器又拋出以下錯誤:npm
The externals config must be Plain Object or Function, but got [object Object]
複製代碼
"externals 配置項必須爲純對象或函數,可是卻獲得了對象形式的數組",因此緣由是 externals 的格式不對:json
externals 配置支持三種形式,分別是 Array、Object 和 Reg,上述的配置項內容是一個對象,因此應該爲用 Object 形式,因此只要把外面的中括號去掉就能夠了:segmentfault
externals: {
'./cptable': 'var cptable',
'../xlsx.js': 'var _XLSX'
}
複製代碼
更多關於 webpack externals 配置的學習,能夠參考:【webpack externals 深刻理解】
運行代碼,在瀏覽器中打開頁面顯示以下: 點擊 Choose File,在本地選擇一個內容以下的 excel 文件:
點擊肯定,上傳後在瀏覽器控制檯查看打印信息:
能夠發現,excel 已經讀取成功而且轉換成了 json 格式的數據,以後就能夠對 json 數據進行分析和處理啦。
使用原生 input 標籤顯示效果比較粗糙,由於對組件簡單地進行了樣式上的美化,效果以下:
針對文件上傳和讀取結果分別作了對應的提示(這裏使用 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;
}
複製代碼