You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular使用dom-to-pdf导出*ngFor动态内容生成空白PDF如何解决

问题原因

你推测的原因正确:Angular的变更检测是异步执行的,你给records赋值后,*ngFor对应的DOM节点还没完成渲染,此时调用domToPdf抓取到的是空的DOM结构,所以导出的PDF是空白的。另外你的模板代码里存在变量名错误,也会导致渲染异常。

解决方案

步骤1:修复模板变量错误

你的模板中遍历体重数据的部分,循环变量名和调用名不一致,修改如下:

<!-- 原来的错误写法 -->
<!-- <p *ngFor="let bloodPressure of record.weights">At {{weight.ReadTime | date:'h:mm a'}}, I weighed {{weight.Weight}}.</p> -->
<!-- 修改为 -->
<p *ngFor="let weight of record.weights">At {{weight.ReadTime | date:'h:mm a'}}, I weighed {{weight.Weight}}.</p>

步骤2:等待DOM渲染完成后再导出PDF

在组件中注入ChangeDetectorRef,手动触发变更检测后,将导出逻辑放到下一个事件循环执行,确保DOM已经渲染完成。
修改后的方法代码如下:

// 首先在组件构造函数中注入ChangeDetectorRef
import { ChangeDetectorRef } from '@angular/core';
constructor(private cdr: ChangeDetectorRef, /* 其他原有依赖 */) {}

generateReport(): void {
  let bloodPressureFilter = `${this.bloodPressure.readDateFrom ? `ReadDate_GreaterEqual=${encodeURIComponent(this.datePipe.transform(this.bloodPressure.readDateFrom, 'YYYY-MM-dd'))}` : ''}`;
  bloodPressureFilter = `${bloodPressureFilter ? '&' : ''}${this.bloodPressure.readDateTo ? `ReadDate_LessEqual=${encodeURIComponent(this.datePipe.transform(this.bloodPressure.readDateTo, 'YYYY-MM-dd'))}` : ''}`;
  let sugarFilter = `${this.sugar.readDateFrom ? `ReadDate_GreaterEqual=${encodeURIComponent(this.datePipe.transform(this.sugar.readDateFrom, 'YYYY-MM-dd'))}` : ''}`;
  sugarFilter = `${sugarFilter ? '&' : ''}${this.sugar.readDateTo ? `ReadDate_LessEqual=${encodeURIComponent(this.datePipe.transform(this.sugar.readDateTo, 'YYYY-MM-dd'))}` : ''}`;
  let weightFilter = `${this.weight.readDateFrom ? `ReadDate_GreaterEqual=${encodeURIComponent(this.datePipe.transform(this.weight.readDateFrom, 'YYYY-MM-dd'))}` : ''}`;
  weightFilter = `${weightFilter ? '&' : ''}${this.weight.readDateTo ? `ReadDate_LessEqual=${encodeURIComponent(this.datePipe.transform(this.weight.readDateTo, 'YYYY-MM-dd'))}` : ''}`;
  forkJoin({
    bloodPressures: this.bloodPressureService.query(bloodPressureFilter),
    sugars: this.sugarService.query(sugarFilter),
    weight: this.weightService.query(weightFilter)
  }).subscribe(results => {
    this.records = [];
    const bloodPressures = this.bloodPressure.visible ? results.bloodPressures : [];
    const sugars = this.sugar.visible ? results.sugars : [];
    const weights = this.weight.visible ? results.weight : [];

    bloodPressures.forEach(bloodPressure => {
      const grouppedObject = this.records.find(record => record.entryDate === bloodPressure.ReadDate);
      if (!grouppedObject) {
        this.records.push({
          entryDate: bloodPressure.ReadDate,
          bloodPressures: [ bloodPressure ]
        });
      } else {
        grouppedObject.bloodPressures = grouppedObject.bloodPressures ?? [];
        grouppedObject.bloodPressures.push(bloodPressure);
      }
    });
    sugars.forEach(sugar => {
      const grouppedObject = this.records.find(record => record.entryDate === sugar.ReadDate);
      if (!grouppedObject) {
        this.records.push({
          entryDate: sugar.ReadDate,
          sugars: [ sugar ]
        });
      } else {
        grouppedObject.sugars = grouppedObject.sugars ?? [];
        grouppedObject.sugars.push(sugar);
      }
    });
    weights.forEach(weight => {
      const grouppedObject = this.records.find(record => record.entryDate === weight.ReadDate);
      if (!grouppedObject) {
        this.records.push({
          entryDate: weight.ReadDate,
          weights: [ weight ]
        });
      } else {
        grouppedObject.weights = grouppedObject.weights ?? [];
        grouppedObject.weights.push(weight);
      }
    });

    // 手动触发变更检测,通知Angular更新DOM
    this.cdr.detectChanges();

    // 将导出逻辑放到setTimeout中,等待DOM渲染完成
    setTimeout(() => {
      const today = new Date();
      const element = document.getElementById('report');
      const options = {
        filename: `${this.datePipe.transform(today, 'yMMdhhmmssa')}.pdf`
      };
      domToPdf(element, options, () => {
        console.log('PDF exported');
        this.records = [];
      });
    }, 0);
  });
}

如果上述方案还是有问题,可以把setTimeout的延时调整为100ms,适配部分复杂DOM的渲染耗时。


内容的提问来源于stack exchange,提问作者David

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 11:48:03