【问题标题】:Angular CDK virtual-scroll infinite loopAngular CDK 虚拟滚动无限循环
【发布时间】:2018-11-04 17:04:43
【问题描述】:

我正在尝试使用 CDK 虚拟滚动为项目列表实现无限循环滚动

我到了放弃的地步。我无法做到这一点,我怎样才能实现 CDK 虚拟滚动?

这是我的代码

import { Component, ViewChild, ChangeDetectionStrategy } from '@angular/core';
import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling';
import { Observable, BehaviorSubject } from 'rxjs';
import { map } from 'rxjs/operators';

@Component({
  selector: 'my-app',
  template: `
   <ng-container *ngIf="infinite | async; let items">

     <cdk-virtual-scroll-viewport itemSize="50" 
                                  (scrolledIndexChange)="nextBatch($event, (items[items.length - 1].index))">
       <div *cdkVirtualFor="let item of items; trackBy: trackByIdx">{{item}}</div>
     </cdk-virtual-scroll-viewport>

   </ng-container>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class AppComponent {

  arr = Array.from({ length: 10 }).map((_, i) => `Item #${i}`);

  offset = new BehaviorSubject<any>({ offset: 0 });
  infinite: Observable<any[]>;

  @ViewChild(CdkVirtualScrollViewport) viewPort: CdkVirtualScrollViewport;


  constructor() {
    this.infinite = this.offset.pipe(
      map((n: any) => this.getBatch(n)),
    );
  }

  getBatch({ offset, loadPrev, loadNext, e }) {
    let arr = [...this.arr];
    if (loadPrev) {
      const last = arr[arr.length - 1];
      return [last, ...arr];
    }
    if (loadNext) {
      const first = arr[0];
      return [...arr, first];
    }
    return arr;
  }

  nextBatch(e, offset) {
    const end = this.viewPort.getRenderedRange().end;
    const start = this.viewPort.getRenderedRange().start;
    const total = this.viewPort.getDataLength();

    if (start === 0) {
      this.offset.next({ offset: offset, loadPrev: true, e });
    }

    if (end === total) {
      this.offset.next({ offset: offset, loadNext: true, e });
    }
  }

  trackByIdx(i) {
    return i;
  }
}

Live stackblitz

【问题讨论】:

    标签: angular angular-cdk


    【解决方案1】:

    我们只需要检查滚动是否滚动到最后一项,然后再滚动回第一项。例如:

    app.component.html

    <cdk-virtual-scroll-viewport class="example-viewport" [itemSize]="itemSize" (scrolledIndexChange)="onScroll($event)">
        <div *cdkVirtualFor="let item of items" class="example-item">{{item}}</div>
    </cdk-virtual-scroll-viewport>
    

    app.component.ts

    items = Array.from({ length: 100 }).map((_, i) => `Item #${i}`);
    itemSize = 5;
    @ViewChild(CdkVirtualScrollViewport) viewPort: CdkVirtualScrollViewport;
    
    onScroll(event) {
        console.log(event);
        if( event >= ((this.items.length-this.itemSize-1)*10) ) {
          this.viewPort.scrollToIndex(0);
        }
    }
    

    https://angular-utnzft.stackblitz.io

    【讨论】:

    • 你能在 stackblitz 中制作它吗?
    • 它在 stackblitz 上的 '(this.items.length-this.itemSize-1)*10' 值不能正常工作,所以我不得不将它硬编码为 820。但是,它正在运行我的本地机器本身有变量值。
    • scrollToIndex(0) 不是无限循环!只要您滚动,数组就应该重复
    【解决方案2】:

    cdk-virtual-scroll-viewport 必须有一个高度,它循环的项目也应该有一个固定的高度。组件需要此信息来计算何时应呈现或移除项目。

    例如

    cdk-virtual-scroll-viewport {
      height: 100vh;
    
      li {
        height: 100px;
      }
    }
    

    【讨论】:

    • 高度是坐着的,但你可能没有检查我提供的stackblitz。这与无限循环有什么关系!
    猜你喜欢
    • 1970-01-01
    • 2019-08-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多