Angular10基于XLSX与file-saver 解决ngx-pagination分页仅导出当前页问题
问题核心原因
导出功能只能导出当前页内容的本质是原导出逻辑完全绕开了传入的全量JSON参数,直接抓取页面DOM生成Excel:
- 代码中已经注释了
json_to_sheet的数据转换分支,改用XLSX.utils.table_to_sheet(element)读取id为excel-table的DOM节点内容 - ngx-pagination的客户端分页机制,仅会把当前页码对应的表格行渲染到DOM中,其余分页的内容不会出现在页面上,因此抓取DOM自然只能拿到当前页的渲染结果,和接口是否返回全量数据无关
- 同时原逻辑没有处理后端返回的
queues嵌套数组,直接转换的话嵌套对象会显示为[object Object],不符合导出预期
落地解决方案
废弃依赖页面DOM的导出逻辑,基于传入的全量JSON数据做适配处理后生成Excel,具体调整如下:
第一步 适配嵌套数据结构
针对后端返回的用户列表嵌套queues数组的结构,做和页面表格展示逻辑一致的扁平化处理,避免导出的Excel出现嵌套对象显示异常的问题。可以根据实际展示规则选择:
- 把单个用户绑定的所有队列拼接成逗号分隔的字符串,合并成一行导出
- 按照页面展示规则,一个用户对应N个队列就拆成N行,重复填充用户基础信息,和分页展示的效果完全对齐
第二步 调整服务层导出逻辑
直接用处理好的全量数据生成工作表,完全不依赖页面渲染的DOM:
// 新增嵌套数据扁平化辅助方法 private flattenUserExportData(rawList: any[]): any[] { const exportRows: any[] = []; rawList.forEach(user => { // 兼容用户未绑定任何队列的边界场景 const userQueues = user.queues?.length ? user.queues : [{}]; // 每个队列对应一行,和页面表格展示逻辑完全对齐 userQueues.forEach(queue => { exportRows.push({ '用户ID': user._id, '用户名': user.userName, '所属部门': user.divisionName || '无', '邮箱': user.emailId, '绑定队列ID': queue.queueRefId || '-', '绑定队列名称': queue.queueName || '-', }) }) }) return exportRows; } public exportAsExcelFile(json: any[], excelFileName: string): void { // 转换带嵌套结构的原始数据为可直接导出的扁平结构 const flatExportData = this.flattenUserExportData(json); // 用全量扁平数据生成工作表,不再读取页面DOM const worksheet: XLSX.WorkSheet = XLSX.utils.json_to_sheet(flatExportData); // 后续生成工作簿、保存文件的逻辑保持不变 const workbook: XLSX.WorkBook = { Sheets: { 'data': worksheet }, SheetNames: ['data'] }; const excelBuffer: any = XLSX.write(workbook, { bookType: 'xlsx', type: 'array' }); this.saveAsExcelFile(excelBuffer, excelFileName); }
可选优化(如果一定要保留DOM转表的效果)
如果不想手写数据扁平化逻辑,想复用现有表格的渲染样式生成导出内容,可以在导出时临时创建一个不在页面显示的全量表格节点,把全量数据渲染的HTML内容塞进这个节点,抓取完成后再删除临时节点即可:
public exportAsExcelFile(json: any[], excelFileName: string): void { // 创建离屏的临时表格,对用户不可见 const tempTable = document.createElement('table'); tempTable.style.position = 'absolute'; tempTable.style.left = '-9999px'; // 按照页面表格的渲染规则,把全量数据生成对应的表头、数据行插入tempTable document.body.appendChild(tempTable); // 抓取全量临时表格生成工作表 const worksheet: XLSX.WorkSheet = XLSX.utils.table_to_sheet(tempTable); // 导出完成后删除临时节点,避免占用DOM内存 document.body.removeChild(tempTable); // 后续保存逻辑保持不变 const workbook: XLSX.WorkBook = { Sheets: { 'data': worksheet }, SheetNames: ['data'] }; const excelBuffer: any = XLSX.write(workbook, { bookType: 'xlsx', type: 'array' }); this.saveAsExcelFile(excelBuffer, excelFileName); }
注意:组件层的调用逻辑不需要调整,原代码已经将接口返回的全量数据传入导出方法,之前的问题根源是服务层没有正确使用这个传入的参数。
内容的提问来源于stack exchange,提问作者Mohan
相关产品推荐
相关产品推荐

