我想在Angular应用程序上使用虚拟滚动。我列表中的项目是远程页面搜索的结果。每当我向下滚动到视口末时,我想加载更多结果(调用下一页)。
这是我的模板:
<div class="container">
<cdk-virtual-scroll-viewport itemSize="100">
<li *cdkVirtualFor="let item of searchResult">{{item}}</li>
</cdk-virtual-scroll-viewport>
</div>
这是我尝试使其按需运行:
export class SearchComponent {
@ViewChild(CdkVirtualScrollViewport) virtualScroll: CdkVirtualScrollViewport;
searchPageNumber: number;
searchResults: Array<any>;
constructor(private scrollDispatcher: ScrollDispatcher, private searchService: SearchService) {
this.searchPageNumber = 0;
this.searchResults = [];
}
ngOnInit(): void {
this.nextSearchPage(this.searchPageNumber);
}
ngAfterViewInit(): void {
//this.scrollDispatcher.register(this.scrollable);
//this.scrollDispatcher.scrolled(1000)
// .subscribe((viewport: CdkVirtualScrollViewport) => {
// console.log('scroll triggered', viewport);
// });
this.virtualScroll.renderedRangeStream.subscribe(range => {
console.log('range', range);
console.log('range2', this.virtualScroll.getRenderedRange());
if (this.virtualScroll.getRenderedRange().end % 10 === 0) {
this.nextSearchPage(++this.searchPageNumber);
}
});
}
nextSearchPage(pageNumber: number): void {
this.searchService.getResults(pageNumber).then((pagedResults) => {
this.searchResults = this.searchResults.concat(pageResuls);
});
}
}
如您所见,仅当滚动条到达列表中当前渲染项目的末尾时,我才能弄清楚如何触发对nextSearchPage
函数的调用(以加载更多结果)。
你知道我该怎么做吗?
如本issue所述,角度滚动文档也很差,并且缺少示例。
答案 0 :(得分:4)
在CdkScrollable上有一个measureMeasureOffOffset函数可能会有所帮助。 您可以订阅滚动事件并检查偏移量以确定滚动位置。
ngAfterViewInit(): void {
this.scrollDispatcher.scrolled().pipe(
filter(event => this.virtualScroll.measureScrollOffset('bottom') === 0)
).subscribe(event => {
this.searchPageNumber++;
this.nextSearchPage(this.searchPageNumber);
})
并且您需要在滚动项目集合更改后手动调用detectChange。尽管我没有找到解决方法,但是有一个问题:更改检测后,滚动条将返回到开始位置。
在此处查看演示:https://stackblitz.com/edit/template-angular7-material-primeng-ckxgzs
编辑:
结果证明,侦听滚动结束可能不是一个好主意。更好的方法是监听渲染范围(我相信这是DOM中渲染的实际项目)的变化。一旦渲染范围结束等于数据长度,就可以将更多数据添加到集合中了。这以某种方式解决了酒吧重新开始的问题。
ngAfterViewInit(): void {
this.scrollDispatcher.scrolled().pipe(
filter(event => this.virtualScroll.getRenderedRange().end === this.virtualScroll.getDataLength())
).subscribe(event => {
this.searchPageNumber++;
this.nextSearchPage(this.searchPageNumber);
})
此处的新演示: https://stackblitz.com/edit/template-angular7-material-primeng-fhikcf
说实话,我的主意是: https://angularfirebase.com/lessons/infinite-virtual-scroll-angular-cdk/ 您可能在那里可以了解更多信息。
答案 1 :(得分:1)
解决此问题的最简单方法是使用 scrolledIndexChange 。
5/16
$ event是当前渲染元素的第一个索引。因此,当第一项的索引接近列表中各项的结尾时,您可以调用下一页。
请记住,这些项目具有固定的高度(itemSize),因此很容易识别一次渲染的元素数量。
例如
<cdk-virtual-scroll-viewport itemSize="500" (scrolledIndexChange)="nextBatch($event)">