导出XLSX表格前如何自定义行数据?
问题描述
现有如下数据数组:
const data = [ { id: 1, serviceId: 1, title: "A", model: "A", }, { id: 1, serviceId: 1, title: "T", model: "b", }, { id: 1, serviceId: 2, title: "R", model: "A", }, { id: 2, serviceId: 55, title: "Q", model: "A", }, { id: 3, serviceId: 58, title: "S", model: "p", }, { id: 3, serviceId: 58, title: "S", model: "m", }, { id: 3, serviceId: 66, title: "y", model: "A", } ];
使用以下ExportToExcel组件将数据导出为XLSX文件:
export const ExportToExcel = ({ apiData, fileName }) => { const fileType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8"; const fileExtension = ".xlsx"; const exportToCSV = (apiData, fileName) => { const ws = XLSX.utils.json_to_sheet(apiData); const wb = { Sheets: { data: ws }, SheetNames: ["data"] }; const excelBuffer = XLSX.write(wb, { bookType: "xlsx", type: "array" }); const data = new Blob([excelBuffer], { type: fileType }); FileSaver.saveAs(data, fileName + fileExtension); }; return ( <Button onClick={(e) => exportToCSV(apiData, fileName)} sx={{ m: 2 }} variant="contained" > Export as xlsx </Button> ); };
组件调用方式:
<ExportToExcel apiData={data} fileName={fileName}/>
希望导出时实现合并相同id、serviceId的行的效果,之前尝试循环分组实现但代码冗余,求更简洁的实现方法。
解决方案
可以利用xlsx库的单元格合并能力,结合分组逻辑快速实现,以下是优化后的代码:
方案1:用Lodash简化分组
先安装Lodash(若未安装):
npm install lodash
修改组件代码:
import _ from 'lodash'; import XLSX from 'xlsx'; import FileSaver from 'file-saver'; import { Button } from '@mui/material'; export const ExportToExcel = ({ apiData, fileName }) => { const fileType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8"; const fileExtension = ".xlsx"; const exportToXLSX = (apiData, fileName) => { // 按id+serviceId组合键分组 const groupedData = _.groupBy(apiData, item => `${item.id}-${item.serviceId}`); // 预处理数据:每组仅第一条保留id和serviceId,其余置空 const processedData = []; Object.values(groupedData).forEach(group => { group.forEach((item, idx) => { processedData.push({ id: idx === 0 ? item.id : '', serviceId: idx === 0 ? item.serviceId : '', title: item.title, model: item.model }); }); }); // 生成工作表 const ws = XLSX.utils.json_to_sheet(processedData); // 初始化合并规则数组 ws['!merges'] = []; // 计算并设置合并范围 let startRow = 1; // 表头占第0行,数据从第1行开始(xlsx行索引从0起) Object.values(groupedData).forEach(group => { const rowLen = group.length; if (rowLen > 1) { // 合并id列(A列,索引0) ws['!merges'].push({ s: { r: startRow, c: 0 }, e: { r: startRow + rowLen - 1, c: 0 } }); // 合并serviceId列(B列,索引1) ws['!merges'].push({ s: { r: startRow, c: 1 }, e: { r: startRow + rowLen - 1, c: 1 } }); } startRow += rowLen; }); // 生成工作簿并导出 const wb = { Sheets: { data: ws }, SheetNames: ["data"] }; const excelBuffer = XLSX.write(wb, { bookType: "xlsx", type: "array" }); const dataBlob = new Blob([excelBuffer], { type: fileType }); FileSaver.saveAs(dataBlob, fileName + fileExtension); }; return ( <Button onClick={(e) => exportToXLSX(apiData, fileName)} sx={{ m: 2 }} variant="contained" > Export as xlsx </Button> ); };
方案2:原生JS分组(无需Lodash)
如果不想引入第三方库,用原生JS的reduce实现分组:
// 替换方案1中的groupBy逻辑 const groupedData = apiData.reduce((acc, item) => { const key = `${item.id}-${item.serviceId}`; acc[key] = acc[key] || []; acc[key].push(item); return acc; }, {});
核心逻辑说明
- 分组:通过
id和serviceId的组合键把数据分成多组; - 数据预处理:每组仅第一条保留
id和serviceId值,其余置空,避免合并后重复显示内容; - 设置合并规则:通过
ws['!merges']数组定义单元格合并范围,每个规则包含起始(s)和结束(e)的行、列索引; - 导出:生成工作簿并通过
FileSaver保存为XLSX文件。
内容的提问来源于stack exchange,提问作者sam12
相关产品推荐
相关产品推荐

