如何用react-data-export一键下载多份Excel并压缩为ZIP?
解决方案:react-data-export实现多Excel文件打包ZIP下载
react-data-export本身不支持多文件打包导出,我们可以结合它底层依赖的xlsx库,加上jszip来实现ZIP打包功能,以下是具体实现步骤:
步骤1:安装依赖
首先安装jszip(用于ZIP打包),如果项目未安装xlsx也需要补充安装:
npm install jszip xlsx --save
步骤2:修改组件代码
替换原有单文件导出逻辑,改为生成多份Excel Blob后打包ZIP下载:
import React, { useState, useEffect } from 'react'; import { Container, Col, Row, Button, Modal, Tooltip } from 'react-bootstrap'; import ReactExport from 'react-data-export'; import JSZip from 'jszip'; import * as XLSX from 'xlsx'; const ExcelFile = ReactExport.ExcelFile; const ExcelSheet = ReactExport.ExcelFile.ExcelSheet; const ExcelColumn = ReactExport.ExcelFile.ExcelColumn; const VesselReportExcelGenerator = (props) => { const [exportModalOpen, setExportModalOpen] = useState(false); const [excelDataList, setExcelDataList] = useState([]); // 存储多份导出数据集 const vesselReportApi = new VesselReportApi(); const loggedInVesselName = JSON.parse(localStorage.getItem('selectedVessel'))?.name; useEffect(() => { fetchMultipleVesselReports(); }, []); // 获取多份需要导出的数据(示例:日报、维护报) const fetchMultipleVesselReports = async () => { try { const dailyLogData = await vesselReportApi.getVesselReportFormStructure(); const maintenanceLogData = await vesselReportApi.getVesselMaintenanceReport(); // 假设存在该接口 setExcelDataList([ { name: 'Daily Log', columns: columns, data: dailyLogData }, { name: 'Maintenance Log', columns: maintenanceColumns, data: maintenanceLogData } // 对应维护报表的列配置 ]); } catch (error) { console.log(error); props.setMessages([{type : "danger", message : 'Something went wrong. Please try again!'}]); } }; // 生成单个Excel文件的Blob对象 const generateExcelBlob = (sheetName, columns, data) => { const dataSet = [{ columns, data }]; const excelFile = new ExcelFile({ filename: sheetName }); excelFile.addSheet(new ExcelSheet({ name: sheetName, dataSet })); const wb = excelFile.generate(); return XLSX.write(wb, { type: 'blob', bookType: 'xlsx' }); }; // 打包所有Excel为ZIP并触发下载 const handleExportZip = async () => { const zip = new JSZip(); // 遍历数据集生成每个Excel文件并加入ZIP for (const item of excelDataList) { const blob = await generateExcelBlob(item.name, item.columns, item.data); zip.file(`${loggedInVesselName}_${item.name}Template.xlsx`, blob); } // 生成ZIP并下载 zip.generateAsync({ type: 'blob' }).then((content) => { const url = URL.createObjectURL(content); const a = document.createElement('a'); a.href = url; a.download = `${loggedInVesselName}_AllReports.zip`; a.click(); URL.revokeObjectURL(url); setExportModalOpen(false); }).catch(error => { console.error('打包ZIP失败:', error); props.setMessages([{type : "danger", message : 'Failed to generate ZIP file. Please try again!'}]); }); }; return ( <Container fluid className="VesselReportExcelBackground"> <Col lg={7}> <Row style={{ justifyContent: 'center', height: '2rem', paddingTop: "40px", height: "10%" }}> <div style={{ fontSize: "2rem", color: config.KSTColors.MAIN, fontWeight: "900" }}> OFFLINE VESSEL REPORT </div> </Row> {/* Export Vessel report excel UI */} <Row xs={12} md={3} style={{ backgroundColor: config.KSTColors.CARD_BG, height: "150px", borderRadius: "15px", marginTop: "40px" }}> <Col xs={3} lg={3} style={{ padding: "0px" }}> <Button className="VesselReportExcelEditButton" style={{ backgroundColor: config.KSTColors.MAIN, borderColor: config.KSTColors.MAIN, width: "100%" }} onClick={() => setExportModalOpen(true)}> <img src={VesselExportIMG} alt="Excel Export" style={{ height: "120px" }}/> </Button> </Col> <Col xs={6} lg={6}> <div style={{ display: "flex", width: "100%", height: "100%", flexDirection: "column", justifyContent: "center" }}> <div style={{ marginTop: "5px", width: "100%", height: "50%", color: config.KSTColors.MAIN, fontSize: "32px", display: "flex", justifyContent: "center", alignItems: "center" }}> Download Template </div> </div> </Col> </Row> </Col> <Modal size="lg" show={exportModalOpen} onHide={() => setExportModalOpen(false)} aria-labelledby="VRTemplateDownload" centered> <Modal.Header style={{ backgroundColor: '#e6e6e6' }}> <Modal.Title id="VRTemplateDownload">Export Vessel Report Template</Modal.Title> </Modal.Header> <Modal.Body> <span style={{ fontSize: "12px" }}>Are you sure to generate all {loggedInVesselName} vessel reports?</span> </Modal.Body> <Modal.Footer style={{ color: '#04588e' }}> <Button onClick={() => setExportModalOpen(false)} style={{ backgroundColor: 'white', color: '#04588e', paddingTop: '2px', paddingBottom: '2px', paddingLeft: '20px', paddingRight: '20px' }}>Cancel</Button> {/* 替换原有单文件按钮为ZIP导出按钮 */} <Tooltip title="Export All Reports as ZIP" placement="bottom"> <Button style={{ backgroundColor: '#04588e', color: 'white', paddingTop: '2px', paddingBottom: '2px', paddingLeft: '20px', paddingRight: '20px' }} onClick={handleExportZip}> All Reports (ZIP) </Button> </Tooltip> </Modal.Footer> </Modal> </Container> ); }; export default withMessageManager(VesselReportExcelGenerator);
关键说明
- 多数据管理:
excelDataList存储所有需要导出的数据集,每个集合包含文件名、列配置和对应数据,可根据实际业务调整数据源。 - Excel Blob生成:复用react-data-export的工作簿生成逻辑,通过
xlsx将工作簿转为Blob格式,确保导出文件格式与原有单文件一致。 - ZIP打包逻辑:使用
jszip遍历所有Blob文件,添加到ZIP包后生成浏览器可下载的链接,完成一键打包下载。 - 错误处理:在打包过程中加入异常捕获,避免前端崩溃并给用户提示。
内容的提问来源于stack exchange,提问作者harizh
相关产品推荐
相关产品推荐

