web端浏览器预览excel(react)
import React, { useState, useEffect } from 'react';
import { read, utils } from 'xlsx';
import { Anchor } from 'antd';
import './index.less';
const prefixCls = 'xt-knowledge-upload-file-preview-excel';
const FilePreviewExcel = ({ excelUrl }) => {
const [excelData, setExcelData] = useState([]);
useEffect(() => {
if (excelUrl) {
fetchExcelStream(excelUrl);
}
}, [excelUrl]);
const fetchExcelStream = async url => {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`无法获取Excel文件: ${response.statusText}`);
}
const blob = await response.blob();
const arrayBuffer = await blob.arrayBuffer();
const data = new Uint8Array(arrayBuffer);
const workbook = read(data, { type: 'buffer' });
const sheetNames = workbook.SheetNames;
const sheetData = sheetNames.map(sheetName => ({
name: sheetName,
data: utils.sheet_to_json(workbook.Sheets[sheetName], { header: 1 }),
}));
setExcelData(sheetData);
} catch (error) {
console.error('获取或处理Excel文件时出错:', error);
}
};
const renderTable = (sheetName, sheetData) => {
const tableId = `excelTable_${sheetName}`;
const tableElement = document.getElementById(tableId);
tableElement.innerHTML = ''; // 清空表格
const thead = document.createElement('thead');
const tbody = document.createElement('tbody');
// 创建表头
const headerRow = document.createElement('tr');
sheetData[0].forEach(cell => {
const th = document.createElement('th');
th.textContent = cell;
headerRow.appendChild(th);
});
thead.appendChild(headerRow);
// 创建数据行
sheetData.forEach((row, index) => {
if (index === 0) return; // 跳过第一行(表头)
const tr = document.createElement('tr');
row.forEach(cell => {
const td = document.createElement('td');
td.textContent = cell;
tr.appendChild(td);
});
tbody.appendChild(tr);
});
tableElement.appendChild(thead);
tableElement.appendChild(tbody);
};
useEffect(() => {
if (excelData.length > 0) {
excelData.forEach(sheet => {
renderTable(sheet.name, sheet.data);
});
}
}, [excelData]);
return (
<div className={`${prefixCls}`} id={`${prefixCls}`}>
<div className={`${prefixCls}-scroll`}>
<div className={`${prefixCls}-scroll-content`}>
<div className={`${prefixCls}-table`}>
{excelData.map((sheet, index) => (
<div key={sheet.name}>
<h3 id={`anchor-${index}-${sheet.name}`}>{sheet.name}</h3>
<table
id={`excelTable_${sheet.name}`}
className='excel-preview-table'
border='1'
style={{ width: '100%' }}
/>
</div>
))}
</div>
<div className={`${prefixCls}-anchor`}>
<Anchor
getContainer={() => document.getElementById('xt-knowledge-upload-file-preview-excel')}
onClick={e => {
e.preventDefault();
}}
>
{excelData.map((sheet, index) => (
<Anchor.Link key={`anchor_${sheet.name}`} href={`#anchor-${index}-${sheet.name}`} title={sheet.name} />
))}
</Anchor>
</div>
</div>
</div>
</div>
);
};
export default FilePreviewExcel;
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了