Angular如何获取动态创建div的高度并传递给兄弟组件?
解决方案:Angular组件间动态传递Carousel高度
针对你遇到的Angular组件间传递动态生成的ngb-carousel高度的问题,我整理了几个实用的解决方案,看看哪个适合你的场景:
方案一:优化BehaviorSubject服务(推荐,组件解耦)
之前用BehaviorSubject出现初始值问题,我们可以把初始值设为null,并在子组件1中处理carousel销毁的情况,子组件2订阅时区分有效高度和无carousel的状态:
1. 创建共享服务
import { Injectable } from '@angular/core'; import { BehaviorSubject, Observable } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class CarouselHeightService { // 初始值设为null,代表还未获取到carousel状态 private carouselHeightSubject = new BehaviorSubject<number | null>(null); carouselHeight$: Observable<number | null> = this.carouselHeightSubject.asObservable(); // 更新高度,支持传递null表示carousel不存在 updateCarouselHeight(height: number | null) { this.carouselHeightSubject.next(height); } }
2. 子组件1中发送高度变化
import { Component, Input, ViewChildren, ViewContainerRef, AfterViewInit } from '@angular/core'; import { CarouselHeightService } from './carousel-height.service'; import { YourAlertService } from './your-alert.service'; // 替换成你的实际服务 @Component({ selector: 'child-component-1', templateUrl: './child-component-1.html' }) export class ChildComponent1 implements AfterViewInit { @Input() id: string; alertFound = false; @ViewChildren('carousel', { read: ViewContainerRef }) viewContainerRefs; constructor( private alertService: YourAlertService, private carouselHeightService: CarouselHeightService ) {} ngOnInit() { this.alertService.checkAlert(this.id).subscribe((result: any) => { this.alertFound = result.alertFound; }); } ngAfterViewInit() { this.viewContainerRefs.changes.subscribe(item => { if (item._results.length > 0) { // 获取carousel高度并发送 const height = item._results[0]._lContainer[0][0].offsetHeight; this.carouselHeightService.updateCarouselHeight(height); } else { // carousel被销毁时,发送null this.carouselHeightService.updateCarouselHeight(null); } }); } }
3. 子组件2中接收并计算高度
import { Component, OnInit, OnDestroy } from '@angular/core'; import { CarouselHeightService } from './carousel-height.service'; import { Subscription } from 'rxjs'; @Component({ selector: 'child-component-2', templateUrl: './child-component-2.html' }) export class ChildComponent2 implements OnInit, OnDestroy { actualHeight: number; private heightSubscription: Subscription; constructor(private carouselHeightService: CarouselHeightService) {} ngOnInit() { // 订阅高度变化 this.heightSubscription = this.carouselHeightService.carouselHeight$.subscribe(height => { if (height !== null) { this.actualHeight = window.innerHeight - height; } else { // 无carousel时使用默认值 this.actualHeight = window.innerHeight - 269; } }); } ngOnDestroy() { // 取消订阅避免内存泄漏 if (this.heightSubscription) { this.heightSubscription.unsubscribe(); } } }
这个方案的优势是组件间完全解耦,不管子组件加载顺序如何,都能实时响应高度变化。
方案二:父组件作为中间层(@Output + @Input 优化)
如果不想用共享服务,可以通过父组件中转状态,解决之前ngOnChanges未触发的问题:
1. 父组件模板与逻辑
<child-component-1 [id]="id" (carouselHeightChange)="handleCarouselHeightChange($event)"></child-component-1> <child-component-2 [carouselHeight]="currentCarouselHeight"></child-component-2>
import { Component } from '@angular/core'; @Component({ selector: 'parent-component', templateUrl: './parent-component.html' }) export class ParentComponent { currentCarouselHeight: number | null = null; handleCarouselHeightChange(height: number | null) { this.currentCarouselHeight = height; } }
2. 子组件1发射高度事件
import { Component, Input, ViewChildren, ViewContainerRef, AfterViewInit, Output, EventEmitter } from '@angular/core'; import { YourAlertService } from './your-alert.service'; @Component({ selector: 'child-component-1', templateUrl: './child-component-1.html' }) export class ChildComponent1 implements AfterViewInit { @Input() id: string; @Output() carouselHeightChange = new EventEmitter<number | null>(); alertFound = false; @ViewChildren('carousel', { read: ViewContainerRef }) viewContainerRefs; constructor(private alertService: YourAlertService) {} ngOnInit() { this.alertService.checkAlert(this.id).subscribe((result: any) => { this.alertFound = result.alertFound; }); } ngAfterViewInit() { this.viewContainerRefs.changes.subscribe(item => { if (item._results.length > 0) { const height = item._results[0]._lContainer[0][0].offsetHeight; this.carouselHeightChange.emit(height); } else { this.carouselHeightChange.emit(null); } }); } }
3. 子组件2监听输入变化
import { Component, Input, OnChanges, SimpleChanges } from '@angular/core'; @Component({ selector: 'child-component-2', templateUrl: './child-component-2.html' }) export class ChildComponent2 implements OnChanges { @Input() carouselHeight: number | null = null; actualHeight: number; ngOnInit() { // 设置初始默认值,避免未收到值时的空白 this.actualHeight = window.innerHeight - 269; } ngOnChanges(changes: SimpleChanges) { // 监听carouselHeight的变化 if (changes['carouselHeight']) { const height = changes['carouselHeight'].currentValue; this.actualHeight = height !== null ? window.innerHeight - height : window.innerHeight - 269; } } }
这个方案适合组件层级简单的场景,逻辑清晰,容易调试。
方案三:子组件2直接监听子组件1(不推荐,耦合性高)
如果一定要让子2直接监听子1的变化,可以通过父组件传递子1的实例,但会增加组件间耦合:
1. 父组件模板
<child-component-1 #child1 [id]="id"></child-component-1> <child-component-2 [child1Instance]="child1"></child-component-2>
2. 子组件2逻辑
import { Component, Input, OnInit, OnDestroy } from '@angular/core'; import { ChildComponent1 } from './child-component-1.component'; import { Subscription } from 'rxjs'; @Component({ selector: 'child-component-2', templateUrl: './child-component-2.html' }) export class ChildComponent2 implements OnInit, OnDestroy { @Input() child1Instance: ChildComponent1; actualHeight: number; private changesSubscription: Subscription; ngOnInit() { if (this.child1Instance?.viewContainerRefs) { this.changesSubscription = this.child1Instance.viewContainerRefs.changes.subscribe(item => { if (item._results.length > 0) { const height = item._results[0]._lContainer[0][0].offsetHeight; this.actualHeight = window.innerHeight - height; } else { this.actualHeight = window.innerHeight - 269; } }); } } ngOnDestroy() { if (this.changesSubscription) { this.changesSubscription.unsubscribe(); } } }
这个方案不推荐,因为子2依赖子1的内部属性,后续子1的代码修改可能导致子2失效。
内容的提问来源于stack exchange,提问作者Timuçin Çiçek
相关产品推荐
相关产品推荐

