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

Angular/PrimeNG中如何让右侧信息卡与左侧折线图高度一致

问题:Angular+PrimeNG中折线图与信息卡全屏时高度同步失效

需求背景

  • 使用PrimeNG Paradise主题,页面包含两个核心组件:折线图(LineChart)、传感器数据信息卡(Information Card)
  • 浏览器全屏时为一行两列布局,要求右侧信息卡高度始终与左侧折线图保持一致

现有实现方案

高度共享服务(height.service.ts)

export class HeightService {
   private height = new BehaviorSubject<string>('');

    setHeight(height: string){
        this.height.next(height)
    }

    getHeight() {
        return this.height.asObservable();
    }
  constructor() { }
}

折线图组件(LineChartComponent)

TypeScript代码

export class LineChartComponent implements OnInit, OnChanges, AfterViewInit, AfterContentInit, OnDestroy{

    dataAvailable: boolean = false;

    @ViewChild('lineChartElement') lineChartElement;
    private containerHeightUpdateInterval: number;

    constructor(private heightService: HeightService) {}

    ngOnInit() {
        setInterval(() => {
            this.setContainerHeight();
        }, 1000)
    }

    @HostListener('window:resize', [])
    onResize() {
        this.setContainerHeight()
    }
    ngAfterViewInit() {
        this.setContainerHeight()
    }

    ngAfterContentInit() {
        this.setContainerHeight()
    }
    setContainerHeight() {
        let height = `${this.lineChartElement.nativeElement.offsetHeight}`;
        this.heightService.setHeight(height);
    }
}

模板代码

<div class="card"  #lineChartElement>
    <div class="card-header">
        <h4>{{title}}</h4>
    </div>
    <div class="card-body">
        <div *ngIf="dataAvailable">
            <p-chart type="line" [data]="showData" [options]="lineOptions" [style]="{'width': '50%'}"></p-chart>
        </div>
    </div>
</div>

信息卡组件(EnergyViewComponent)

TypeScript代码

export class EnergyViewComponent implements OnInit, OnChanges, AfterViewInit{
    dataAvailable = false;

    //containerHeight -> inherit from LineChart
    containerHeight: string;

    constructor(private heightService: HeightService) {}

    ngOnInit(): void {

        this.heightService.getHeight().subscribe((height) => {
            this.containerHeight = height;
        })

        setInterval(() => {
            this.getContainerHeight();
        }, 1000)
    }

    ngAfterViewInit() {
        this.heightService.getHeight().subscribe((height) => {
            this.containerHeight = height;
        })
    }

    getContainerHeight() {
        //TODO: Fix alignment when page is in fullscreen
        //TODO: set new Containerheight when orientaiton of mobile device is changing
        this.heightService.getHeight().subscribe((height) => {
            this.containerHeight = height;
        })
    }
}

模板代码

<div *ngIf="sensorType == 'Shelly3EMPro'">
        <div class="card summary" [style.min-height.px]="containerHeight"> <!-- TODO: Find some solution to get containers with same height -->
       <!--<div class="card summary"> -->
        <div class="card-header">
            <h5>{{title}}</h5>
        </div>
        <div *ngIf="dataAvailable" class="grid p-nogutter">

            <div class="col-6 md:col-3"> <!-- There are exactly 6 of this elements, all styled the same -->
                <div class="summary-item blue" [style.opacity]="selectedDateIsToday ? 1 : 0.2">
                    <h5>Aktuelle Leistung</h5>
                    <h3>10 kW</h3>
                </div>
            </div>
        
    </div>
</div>

组件调用代码

<div *ngIf="dataAvailable">
        <div *ngFor="let item of sensorIds">
            <div class="grid p-fluid " style="display: flex; flex-direction: row; flex-wrap: wrap;" >
                <app-line-chart class="col-6" style="flex-wrap: wrap;" ></app-line-chart>
                <app-energy-view class="col-6" style="flex-wrap: wrap;"></app-energy-view>
            </div>
        </div>
    </div>

当前问题

  • 浏览器全屏时,信息卡的min-height设置完全失效
  • 打开Chrome DevTools调整浏览器尺寸后,信息卡能更新为正确高度,但返回全屏模式后问题复现

问题根源与修复方案

1. 缺失全屏状态变化监听

浏览器进入/退出全屏不会触发标准resize事件,需单独监听全屏相关事件:

// LineChartComponent.ts
ngOnInit() {
    this.setContainerHeight();
    // 监听全屏状态变化
    const updateHeight = this.setContainerHeight.bind(this);
    document.addEventListener('fullscreenchange', updateHeight);
    document.addEventListener('webkitfullscreenchange', updateHeight);
    document.addEventListener('mozfullscreenchange', updateHeight);
}

ngOnDestroy() {
    // 销毁时移除监听,避免内存泄漏
    const updateHeight = this.setContainerHeight.bind(this);
    document.removeEventListener('fullscreenchange', updateHeight);
    document.removeEventListener('webkitfullscreenchange', updateHeight);
    document.removeEventListener('mozfullscreenchange', updateHeight);
}

2. 重复订阅导致内存泄漏与异常

EnergyViewComponent中多次重复订阅高度流,需清理冗余订阅并添加销毁逻辑:

// EnergyViewComponent.ts
import { Subscription } from 'rxjs';

export class EnergyViewComponent implements OnInit, OnDestroy{
    dataAvailable = false;
    containerHeight: number;
    private heightSubscription: Subscription;

    constructor(private heightService: HeightService) {}

    ngOnInit(): void {
        this.heightSubscription = this.heightService.getHeight().subscribe((height) => {
            this.containerHeight = height;
        });
    }

    ngOnDestroy() {
        this.heightSubscription?.unsubscribe();
    }
}

3. 高度值类型不匹配

传递字符串格式的高度会导致[style.min-height.px]解析异常,需改为数值类型传递:

// LineChartComponent.ts
setContainerHeight() {
    const height = this.lineChartElement.nativeElement.offsetHeight;
    this.heightService.setHeight(height); // 传递数值而非字符串
}

4. Flex布局冲突

父容器同时使用PrimeNG grid类和自定义flex样式,简化布局:

<div *ngIf="dataAvailable">
    <div *ngFor="let item of sensorIds">
        <div class="grid p-fluid">
            <app-line-chart class="col-6"></app-line-chart>
            <app-energy-view class="col-6"></app-energy-view>
        </div>
    </div>
</div>

5. 改用height替代min-height

若要求高度严格一致,直接设置height比min-height更可靠:

<div class="card summary" [style.height.px]="containerHeight">

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 21:45:08