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;

 

posted @   上官靖宇  阅读(51)  评论(0编辑  收藏  举报
编辑推荐:
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
阅读排行:
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
点击右上角即可分享
微信分享提示