Виртуализация больших списков с помощью Angular CDK

Чтобы большие списки быстрее реагировали на действия пользователя, реализуйте виртуальную прокрутку.

Stephen Fluin
Stephen Fluin

Прокручиваемый список – один из самых распространенных шаблонов интерфейса. Он используется и в лентах социальных сетей с бесконечной прокруткой, и в корпоративных панелях управления. Если списки прокрутки становятся очень длинными (сотни, тысячи или сотни тысяч элементов), производительность приложения может снизиться.

Большие списки могут загружаться медленно, поскольку приложению необходимо загрузить и отобразить все данные сразу. Они также могут медленно отображаться и перемещаться , поскольку каждый элемент в списке может содержать расширенные данные, мультимедиа и функциональные возможности.

Это может привести к проблемам при загрузке или прокрутке страницы, что вызовет у пользователей раздражение и заставит их покинуть сайт.

Виртуальная прокрутка в Angular с помощью Component Dev Kit

Виртуальная прокрутка – это основной метод, используемый для решения этих проблем масштабирования. Виртуальная прокрутка создает впечатление очень большого списка, предоставляя полосу прокрутки соответствующего размера и возможность навигации по списку без необходимости хранить весь список в памяти или отображать его на странице.

В Angular виртуальная прокрутка обеспечивается Component Dev Kit (CDK). Изменив способ итерации по спискам и предоставив пару дополнительных параметров конфигурации, виртуальная прокрутка CDK будет автоматически управлять виртуальным рендерингом ваших списков, повышая производительность и скорость отклика страницы.

Вместо того чтобы отображать весь список за раз, будет отображаться только подмножество элементов, которые помещаются на экране (плюс небольшой буфер). По мере навигации пользователя рассчитывается и отображается новый набор элементов, при необходимости повторно используя существующий DOM.

В оставшейся части этой статьи рассказывается, как настроить базовую виртуальную прокрутку. Полный рабочий пример можно посмотреть в этом примере приложения:

Настройка виртуальной прокрутки

Сначала убедитесь, что вы установили @angular/cdk с помощью менеджера пакетов. Чтобы установить его с помощью npm, выполните в терминале следующую команду:

npm install --save @angular/cdk

Добавьте ScrollingModule в свое приложение

После установки CDK импортируйте ScrollingModule, который обрабатывает виртуальную прокрутку, из пакета @angular/cdk/scrolling. Затем добавьте его в массив импорта вашего модуля:

import {ScrollingModule} from '@angular/cdk/scrolling';

...
imports: [
  ScrollingModule
...
]
...

Как создать область просмотра

Чтобы посмотреть, как работает пакет,попробуйте создать компонент со списком чисел от 0 до 99 999:

@Component({
  template: `<div *ngFor="let item of list">{{item}}</div>`
})
export class ScrollComponent {
  list = Array.from({length: 100000}).map((_, i) => i);
}

Когда браузер отрисовывает приложение, ему приходится отрисовывать 100 000 отдельных элементов <div>. Это может быть приемлемо для простых текстовых узлов, но любая сложность в повторяющемся шаблоне плохо масштабируется, а количество прослушивателей событий значительно увеличится.

Чтобы добавить виртуальную прокрутку и избежать этих проблем, необходимо создать область просмотра, обернув список в элемент <cdk-virtual-scroll-viewport>:

@Component({
  template: `<cdk-virtual-scroll-viewport>
    <div *ngFor="let item of list">{{item}}</div>
    </cdk-virtual-scroll-viewport>`
})
export class ScrollComponent {
  list = Array.from({length: 100000}).map((_, i) => i);
}

Поскольку ScrollingModule динамически отображает подмножества списка, вам необходимо указать высоту области просмотра с помощью стандартного CSS. Также необходимо указать itemSize, чтобы сообщить области просмотра о ее контенте. Модуль использует эту информацию, чтобы определить, сколько элементов нужно хранить в DOM в определенный момент времени и как отобразить полосу прокрутки соответствующего размера.

@Component({
  template: `<cdk-virtual-scroll-viewport itemSize="18" style="height:80vh">
    <div *ngFor="let item of list">{{item}}</div>
    </cdk-virtual-scroll-viewport>`
})
export class ScrollComponent {
  list = Array.from({length: 100000}).map((_, i) => i);
}

Наконец, преобразуйте *ngFor в *cdkVirtualFor:

@Component({
  template: `<cdk-virtual-scroll-viewport itemSize="18" style="height:80vh">
    <div *cdkVirtualFor="let item of list">{{item}}</div>
    </cdk-virtual-scroll-viewport>`
})
export class ScrollComponent {
  list = Array.from({length: 100000}).map((_, i) => i);
}

Вместо того чтобы перебирать весь список, область просмотра динамически определяет и перебирает правильный поднабор списка для пользователя. Теперь, когда пользователь загружает страницу, CDK должен отобразить подмножество списка, которое помещается на экране (плюс небольшой буфер), а любые события прокрутки в области просмотра загружают и отображают соответствующее подмножество списка:

CDK отрисовывает подмножества списка по мере прокрутки.

Дальнейшие действия

Возможности виртуальной прокрутки CDK выходят далеко за рамки этого базового примера. В примере приложения весь список находился в памяти, но в более сложных приложениях его можно получать по запросу. Подробнее о других возможностях ScrollingModule и директиве cdkVirtualOf можно узнать из раздела о Scrolling в документации по CDK.