Бесконечный цикл виртуальной прокрутки Angular CDK

Я пытаюсь реализовать прокрутку бесконечного цикла для списка элементов с помощью виртуальной прокрутки 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


person Murhaf Sousli    schedule 04.11.2018    source источник


Ответы (2)


Нам просто нужно проверить, прокручивается ли прокрутка до последнего элемента, а затем вернуться к первому элементу. Например:

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

person Learning    schedule 04.11.2018
comment
вы можете произвести это в стеке? - person Murhaf Sousli; 05.11.2018
comment
он не работал правильно со значением '(this.items.length-this.itemSize-1) * 10' в stackblitz, поэтому мне пришлось жестко запрограммировать его как 820. Но он работает на моем локальном компьютере с самими значениями переменных. - person Learning; 05.11.2018
comment
scrollToIndex(0) - это не бесконечный цикл! массив должен повторяться, пока вы прокручиваете - person Murhaf Sousli; 05.11.2018

Окно cdk-virtual-scroll-viewport должно иметь высоту, и элементы, которые он перебирает, также должны иметь фиксированную высоту. Эта информация нужна компоненту, чтобы вычислить, когда элемент должен быть отображен или удален.

E.g

cdk-virtual-scroll-viewport {
  height: 100vh;

  li {
    height: 100px;
  }
}
person Muhammad Kamran    schedule 04.11.2018
comment
Высота указана, но вы, вероятно, не проверили предоставленный мной stackblitz. Как это связано с бесконечным циклом! - person Murhaf Sousli; 04.11.2018