Angular 如何获取动态创建的 div 的高度并将其发送到同级组件?

Angular how to get height of dynamically created div and send it to sibling component?

我有一个 parent2 child components 如下所示

Parent-component.html

<child-component-1 [id]="id"></child-component-1>
<child-component-2></child-component-2>

child-component-1 有 ngb-carousel 组件向 user.And 显示警告和警报 由于 id 而创建此组件,其 result 来自 API 如下所示

child-component-1.ts

alertFound;

this.service.checkAlert(id).subscribe((result:any)=>{
 if(result.alertFound){
 this.alertFound=true;
}
})

child-component-1.html

<ngb-carousel #carousel *ngIf="alertFound" class="carousel-alert" [interval]="false" [wrap]="false"
  [showNavigationIndicators]="false">
........................(Things go on here after result comes)
</ngb-carousel>

child-component-2中,我需要得到这个ngb-alertheight来对它存在的screen.If进行动态高度计算,我需要从中减去它window.innerheight.

child-component-2.html

<div [style.height.px]="actualHeight"></div>

child-component-2.ts

this.actualHeight = window.innerHeight - 269;

有趣的是 child-component-1 当我试图像下面那样跟踪它时

@ViewChild('carousel', {read: ElementRef, static:false}) elementView: ElementRef;

ngAfterViewInit(){
  console.log(this.elementView.nativeElement.offSetHeight);
  //throws height of created carousel first,then if next id doesnt have alert still shows me the height which previously created
}

它显示之前创建的 carousel 高度,即使结果是 falsecarousel 无法创建 moment.I 猜想发生这种情况是因为结果有时会非常晚了,有时 fast.To 监听 viewchild 上的检测 我发现像下面这样的东西完全按照我想要的方式工作并解决了发射 non-created 警报高度问题

  @ViewChildren('carousel', {read: ViewContainerRef}) viewContainerRefs;

      ngAfterViewInit() {
        this.viewContainerRefs.changes.subscribe(item => {
          if (item) {
             console.log(item._results[0]._lContainer[0][0].offsetHeight);
          }
        })
      }

现在的问题是将这个高度发送到 child-component-2,我应该在那里动态计算高度。

我考虑过 2 options.First 一个是在服务上创建主题,从 child-component-1 向它发射高度并在 child-component-2 上收听它,如下所示

service.ts

  alertActive = new BehaviorSubject(0);
  setAlertHeight(value:number){
    this.alertActive.next(value)
  }

child-component-1

  ngAfterViewInit() {
    this.viewContainerRefs.changes.subscribe(item => {
      if (item) {
       this.service.setAlertHeight(item._results[0]._lContainer[0][0].offsetHeight);
      }
    })
  }

child-component-2

this.alertActive.subscribe(value=>{
 if(value){
   this.actualHeight-=value;
  }
})

在上面的例子中,它会导致问题带来高度,即使警报未 created.I 从 child-2child-1 登录控制台并注意到 child-2 打印到控制台,即使 child1 没有向它发出任何东西。

所以我考虑了另一种选择,通过@Output 将高度从 child-1 发送到 parent,然后通过 Input 发送到 child2 个赞

child-1

  @Output() transferHeight: EventEmitter<any> = new EventEmitter();
  this.viewContainerRefs.changes.subscribe(item => {
      if (item) {
      this.transferHeight.emit(item._results[0]._lContainer[0][0].offsetHeight);
      }
    })

parent

    <child-component-1 (transferHeight)="transferedHeight($event)" [id]="id"></child-component-1>
    <child-component-2  [transferredHeight]="transferredHeight"></child-component-2>
 alertHeight;
 transferedHeight(comingHeight){
    this.alertHeight=comingHeight;
  }
  

child-2

  @Input() transferredHeight;
  ngOnInit(){
    this.actualHeight-=this.transferredHeight;
   }

这个真的解决了我提到的问题 previously.But 如果轮播是在 child-2 之后创建的,因为延迟网络恢复,它 returns undefined.Therefore 我试过了使用 ngOnChanges 监听输入变量的变化,如下所示

   ngOnChanges(changes: SimpleChanges) {
    console.log(changes.transferredHeight.currentValue)
} 

这个console.log虽然我实现了onChanges.So但没有打印任何东西我在等你help.If有一种方法可以从child-1中收听viewContainerRefs.changes child-2 是最好的情况

这次尝试的原因:

alertActive = new BehaviorSubject(0);
setAlertHeight(value:number){
  this.alertActive.next(value)
}

即使警报未处于活动状态也会触发要设置的高度是因为您使用了 BehaviorSubject 而不仅仅是 SubjectBehaviorSubject 提供初始值(在您的情况下为 0),因此订阅者将在订阅后立即收到该初始值(或最新发出的值)。

所以你是在正确的轨道上,你只需要使用常规的 Subject 来代替,因为这样订阅者在 Subject 发出之前不会收到任何值。

因此您的服务可能如下所示:

private _alertActive = new Subject<number>();
get alertActive(): Observable<number> {
  return this._alertActive.asObservable();
}

setAlertHeight(height: number) {
  this._alertActive.next(height);
}

(请注意,Subject 是私有成员,但通过 getter 作为 Observable 公开。一般来说,订阅者不应该访问原始 Subject,除非他们也从中散发出价值。)

你的 child-2 组件会像这样订阅它:

this.service.alertActive.subscribe((height: number) => {
  this.actualHeight -= height;
});

您使用 ViewChildren 并订阅它的 changes 也是正确的,但如果您引用 ElementRef 而不是 ViewContainerRef 可能会更简单]s。看起来像这样:

import { NgbCarousel } from "@ng-bootstrap/ng-bootstrap";

@ViewChildren(NgbCarousel, { read: ElementRef }) carousels: QueryList<ElementRef>;


ngAfterViewInit() {
  this.carousels.changes.subscribe((els: QueryList<ElementRef>) => {
    const height = els.first ? els.first.nativeElement.offsetHeight : 0;
    this.service.setAlertHeight(height);
  });
}

Here's a StackBlitz 显示它使用这种方法。