如何在Angular Universal服务端使用jsPDF生成PDF文件?
Angular Universal 服务端渲染导出分页表格PDF实现示例
前置准备
首先完成依赖安装和组件改造:
- 安装所需依赖:
npm install jspdf jspdf-autotable @angular/ssr express - 给现有data grid组件新增导出模式输入参数,开启时关闭分页、渲染全量数据,避免分页逻辑干扰导出结果
示例组件改造代码:
// data-grid.component.ts @Component({ selector: 'app-data-grid', templateUrl: './data-grid.component.html', styleUrls: ['./data-grid.component.css'] }) export class DataGridComponent { // 原有组件参数 @Input() pageSize = 20; @Input() currentPage = 1; // 新增导出专用参数 @Input() exportMode = false; @Input() fullExportData: any[] = []; @Input() columns: {field: string, header: string}[] = []; }
对应组件模板新增全量渲染逻辑:
<!-- 原有分页模式展示 --> <div *ngIf="!exportMode"> <table> <tr *ngFor="let row of pagedData"> <td *ngFor="let col of columns">{{row[col.field]}}</td> </tr> </table> <app-pagination></app-pagination> </div> <!-- 导出模式全量展示 --> <table class="export-table" *ngIf="exportMode"> <thead> <tr> <th *ngFor="let col of columns">{{col.header}}</th> </tr> </thead> <tbody> <tr *ngFor="let row of fullExportData"> <td *ngFor="let col of columns">{{row[col.field]}}</td> </tr> </tbody> </table>
Express 接口与服务端渲染逻辑
在Angular Universal的server.ts文件中新增导出接口,实现服务端渲染组件+生成PDF的完整逻辑:
// server.ts import { renderComponent } from '@angular/core/server'; import { DataGridComponent } from './app/data-grid/data-grid.component'; import jsPDF from 'jspdf'; import autoTable from 'jspdf-autotable'; import express from 'express'; const server = express(); server.use(express.json({limit: '50mb'})); // 配置大文件请求限制,适配大数据量导出 // PDF导出接口 server.post('/api/export-grid-pdf', async (req, res) => { try { // 方案1:从请求体获取全量数据,也可以直接在服务端查询数据库获取,避免前端传输大数据 const { fullExportData, columns } = req.body; // 若需要完全复用组件现有样式,可先渲染组件拿到完整HTML const renderedHtml = await renderComponent(DataGridComponent, { inputs: { exportMode: true, fullExportData, columns }, enableHydration: false, // 关闭hydration提升渲染性能 document: '<!DOCTYPE html><html><head><link rel="stylesheet" href="dist/browser/styles.css"></head><body></body></html>' // 引入全局样式保证渲染效果和前端一致 }); // 方案2:大数据量优先选择直接用数据生成PDF,性能更高 const doc = new jsPDF('landscape', 'mm', 'a4'); doc.setFontSize(12); doc.text('表格导出结果', 10, 15); autoTable(doc, { head: [columns.map(col => col.header)], body: fullExportData.map(row => columns.map(col => row[col.field])), startY: 20, headStyles: { fillColor: '#1976d2', textColor: '#fff' }, alternateRowStyles: { fillColor: '#f5f5f5' }, pageBreak: 'auto', rowPageBreak: 'auto', // 配置固定表头,每页都显示表头 didDrawPage: (data) => { doc.text('表格导出结果', 10, 15); } }); // 返回PDF文件 const pdfBuffer = doc.output('arraybuffer'); res.setHeader('Content-Type', 'application/pdf'); res.setHeader('Content-Disposition', 'attachment; filename="grid-export.pdf"'); res.status(200).send(Buffer.from(pdfBuffer)); } catch (err) { res.status(500).send('PDF生成失败'); } }); // 其他原有服务端逻辑
核心注意事项
- 数千行大数据量场景优先选择直接用数据调用autoTable生成PDF,比解析渲染后的HTML生成效率高3-5倍,内存占用更低
- 若需要1:1复用前端组件样式,可使用jsPDF的
html()方法传入渲染后的组件HTML生成PDF,需提前加载对应样式文件 - 服务端接收前端传的全量数据时,要调整express的请求体大小限制,避免大数据量请求被拦截
- 生成的PDF直接以arraybuffer形式返回,不要在服务端本地落盘,减少IO开销和存储占用
内容的提问来源于stack exchange,提问作者AR_progrmr
相关产品推荐
相关产品推荐

