在ngAfterViewInit中检索由ngFor创建的元素

时间:2018-03-11 23:30:09

标签: javascript angular

我在Angular(5)应用中实现了一个懒惰的图片加载器,我很好奇如果可能的话,我可以避免在我的setTimeout()中调用ngAfterViewInit()

代码的相关部分是:

# component
ngOnInit(): void {
  this.workService.getCategories().then(workCategories => {
    this.workCategories = workCategories;
  });
}

ngAfterViewInit(): void {
  setTimeout(() => {
    const images = Array.from(document.querySelectorAll('.lazy-image'));
  }, 100);
}

# component template
<div *ngFor="let workCategory of workCategories">
  <h3>{{ workCategory.fields.name }}</h3>
  <div *ngFor="let workSample of workCategory.fields.workSamples">
    <img width="294" height="294" class="lazy-image" src="..." data-src="..." />
  </div>
</div>

如果我删除setTimeout(),则图像数组始终为空。 AfterViewInit应在创建所有子组件后运行。我还尝试过AfterContentInit,它的行为与AfterContentChecked相同,后者崩溃了Chrome。

在这种情况下是否可以避免使用setTimeout?

2 个答案:

答案 0 :(得分:1)

This stackblitz显示了使用ngFor指令创建元素时获得通知的方法。在模板中,您将模板引用变量#lazyImage分配给img元素:

<div *ngFor="let workCategory of workCategories">
  ...
  <div *ngFor="let workSample of workCategory.fields.workSamples">
    <img #lazyImage width="294" height="294" class="lazy-image" src="..." data-src="..." />
  </div>
</div>

在代码中,@ViewChildren("lazyImage")用于声明与这些图片相关联的QueryList<ElementRef>。通过订阅changesQuerylist的{​​{1}}事件,您会在元素可用时收到通知。然后可以从ngAfterViewInit

中检索HTML元素
QueryList

如果只处理最后创建的项目,可以使用import { Component, ViewChildren, AfterViewInit, QueryList } from '@angular/core'; @Component({ ... }) export class AppComponent { @ViewChildren("lazyImage") lazyImages: QueryList<ElementRef>; ngAfterViewInit() { this.lazyImages.changes.subscribe(() => { let images = this.lazyImages.toArray().map(x => x.nativeElement); }); } }

QueryList.last

答案 1 :(得分:0)

您可以使用requesAnimationFrame API。

你的问题是,即使Angular告诉浏览器渲染图像,它们还没有呈现,它需要一些时间来更新DOM,这就是你的数组为空的原因。 / p>

requestAnimationFrame API要求浏览器在渲染完成时(通过回调方法)告诉您何时完成当前任务。

ngAfterViewInit(): void {
  window.requestAnimationFrame(() => {
    //place your code here
  })
}