一开始使用xlsx插件,转换的方法是XLSX.utils.sheet_to_json,再去map渲染数据,但是无法渲染多表头的的表格文件,最后使用XLSX.utils.sheet_to_html完美解决。
- 安装xlsx
npm install xlsx
- 在页面中引入
import * as XLSX from 'xlsx';
- 定义解析 excel 对象的方法
const fetchData = async (sheetName?: string) => {
if (!sheetName) {
setDefaultSheetName("");
}
const response = await fetch(url);
const blob = await response.blob();
const reader = new FileReader();
reader.onload = function (e) {
if (e.target) {
// 格式化数组
const data = new Uint8Array(e.target.result as ArrayBuffer);
// 读取文件内容
const workbook = XLSX.read(data, { type: "array" });
// 如果指定了 sheetName,则将其用于查找工作表;否则,使用默认的第一个工作表。
const worksheet = sheetName
? workbook.Sheets[sheetName]
: workbook.Sheets[workbook.SheetNames[0]];
// 将工作表数据转换为 html 格式
const jsonData: any = XLSX.utils.sheet_to_html(worksheet);
setHtmlCode(jsonData);
// 将工作区转为options需要的格式
const newSheetNames = workbook.SheetNames.map((item) => ({
label: item,
value: item,
}));
// 保存工作区
setSheetNames(newSheetNames);
// 设置默认工作区
setDefaultSheetName(sheetName ? sheetName : newSheetNames[0].value);
}
};
reader.readAsArrayBuffer(blob);
};
全部代码
import React, { useEffect, useState } from "react";
import * as XLSX from "xlsx";
import styles from "./excel-renderer.module.scss";
import { Radio, RadioChangeEvent } from "antd";
interface ExcelRendererProps {
url: string;
}
interface sheetNamesSelectType {
label: string;
value: string;
}
const ExcelRenderer: React.FC<ExcelRendererProps> = ({ url }) => {
const [htmlCode, setHtmlCode] = useState("");
const [defaultSheetName, setDefaultSheetName] = useState<string>(""); // 默认工作表
const [sheetNames, setSheetNames] = useState<sheetNamesSelectType[]>([]); // 工作表列表
const fetchData = async (sheetName?: string) => {
if (!sheetName) {
setDefaultSheetName("");
}
const response = await fetch(url);
const blob = await response.blob();
const reader = new FileReader();
reader.onload = function (e) {
if (e.target) {
// 格式化数组
const data = new Uint8Array(e.target.result as ArrayBuffer);
// 读取文件内容
const workbook = XLSX.read(data, { type: "array" });
// 如果指定了 sheetName,则将其用于查找工作表;否则,使用默认的第一个工作表。
const worksheet = sheetName
? workbook.Sheets[sheetName]
: workbook.Sheets[workbook.SheetNames[0]];
// 将工作表数据转换为 html 格式
const jsonData: any = XLSX.utils.sheet_to_html(worksheet);
setHtmlCode(jsonData);
// 将工作区转为options需要的格式
const newSheetNames = workbook.SheetNames.map((item) => ({
label: item,
value: item,
}));
// 保存工作区
setSheetNames(newSheetNames);
// 设置默认工作区
setDefaultSheetName(sheetName ? sheetName : newSheetNames[0].value);
}
};
reader.readAsArrayBuffer(blob);
};
// 工作区
const handleChange = ({ target: { value } }: RadioChangeEvent) => {
fetchData(value);
};
useEffect(() => {
fetchData();
}, [url]);
return (
<div className={styles["excel-container"]}>
{/* 切换工作区 */}
{defaultSheetName && (
<div className="mb-8">
<Radio.Group
defaultValue={defaultSheetName}
options={sheetNames}
optionType="button"
buttonStyle="solid"
onChange={handleChange}
></Radio.Group>
</div>
)}
<div dangerouslySetInnerHTML={{ __html: htmlCode }} />
</div>
);
};
export default ExcelRenderer;
样式
.excel-container{
margin-top: 20px;
overflow: auto;
width: fit-content;
/* Table样式 */
table {
width: 100%;
border-collapse: collapse;
border: 1px solid #ddd;
}
th,
td {
min-width: 80px;
padding: 8px;
text-align: center;
border-bottom: 1px solid #ddd;
border-right: 1px solid #ddd;
}
th {
background-color: #f2f2f2;
font-weight: bold;
}
/* 行样式 */
tr:nth-child(even) {
background-color: #f9f9f9;
}
}