Angular - 避免 setTimeout() hack 来获取 div 宽度

nst*_*ant 3 dom event-handling dom-events angular angular-lifecycle-hooks

编写了一个 Angular 13 组件,每当窗口大小调整时,它都会在 div 中绘制一些内容。

问题是获取 div 的渲染宽度。如果我不使用 setTimeout() 并延迟 170 毫秒,this.treemap.nativeElement.offsetWidth则为零。

由于树形图必须在每次调整窗口大小时重新渲染,我还尝试从 ngAfterViewInit() 调度窗口调整大小事件,但它似乎也发生得太快(所以再次this.treemap.nativeElement.offsetWidth为零)。

模板的相关部分...

  <div #treemap class="treemap col-12"></div>
Run Code Online (Sandbox Code Playgroud)

和缩写代码...

// Details omitted for brevity
export class TreemapComponent implements AfterViewInit {
  @ViewChild('treemap') treemap!: ElementRef

  @HostListener('window:resize', ['$event'])
  private render() {
    const width = this.treemap.nativeElement.offsetWidth
    // code that successfully renders a treemap in the div as long as width != 0
  }

  callHack(): void {
    setTimeout(() => this.render(), 170) // testing shows 170ms is lowest possible
  }

  ngAfterViewInit(): void {
    this.callHack()
    // window.dispatchEvent(new Event('resize')) // happens too fast (offsetWidth = 0)
  }
Run Code Online (Sandbox Code Playgroud)

AfterViewInit 是否是错误的生命周期事件挂钩(这篇文章建议使用 ngAfterViewInit)?

有没有一种更简单的方法可以在 Angular 13 中实现此功能?

Chr*_*ton 5

您可以使用 aResizeObserver来观察元素本身而不是窗口。

export class TreemapComponent implements AfterViewInit, OnDestroy {
  @ViewChild('treemap') treemap!: ElementRef;
  treemapObserver = new ResizeObserver(() => this.render());

  private render() {
    const width = this.treemap.nativeElement.offsetWidth;
    // code that successfully renders a treemap in the div as long as width != 0
  }

  ngAfterViewInit(): void {
    this.treemapObserver.observe(this.treemap.nativeElement);
  }

  ngOnDestroy() {
    this.treemapObserver.unobserve(this.treemap.nativeElement);
  }
}
Run Code Online (Sandbox Code Playgroud)

归功于此答案:/sf/answers/2751876571/