我在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?
答案 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>
。通过订阅changes
中Querylist
的{{1}}事件,您会在元素可用时收到通知。然后可以从ngAfterViewInit
:
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
})
}