17

我想在我的 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如您所见,仅当滚动条到达列表中当前呈现项目的末尾时,

你知道我该怎么做吗?

Angular 滚动文档很差,并且缺少示例,如本期所述。

4

2 回答 2

16

CdkScrollable 上有一个函数 measureScrollOffset 可能会有所帮助。您可以订阅滚动事件并检查偏移量以确定您滚动的位置。

  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/ 您可能可以在那里了解更多信息。

于 2019-02-23T17:27:35.780 回答
5

解决这个问题的最简单方法是使用scrolledIndexChange

<cdk-virtual-scroll-viewport itemSize="500" (scrolledIndexChange)="nextBatch($event)">

$event 是当前渲染元素的第一个索引。因此,当第一个项目的索引接近列表中项目的末尾时,您可以调用下一页

请记住,项目具有固定的高度 (itemSize),因此很容易识别一次渲染的元素数量。

例如

  nextBatch(index) {
    if (index + $itemsRenderAtTheMoment === this.items.length - 1) {
      this.page ++;
      this.loadMore();
    }
  }
于 2020-01-30T13:06:21.743 回答