使用 Angular CDK 虚拟化大型列表

通过实现虚拟滚动,提高大型列表的响应能力。

Stephen Fluin
Stephen Fluin

滚动列表是当今最常见的界面模式之一,无论是在您喜爱的社交媒体网站上浏览无限滚动动态,还是浏览企业信息中心,当滚动列表变得非常长(包含数百、数千或数十万个项)时,应用性能可能会受到影响。

由于应用必须预先加载并渲染所有数据,因此大型列表的加载速度可能会很慢。由于列表中的每个项都可能包含丰富的数据、媒体和功能,因此它们的呈现和导航速度也可能会较慢。

用户在加载或滚动网页时可能会遇到问题,导致他们感到沮丧并放弃网页。

使用 Component Dev Kit 在 Angular 中实现虚拟滚动

虚拟滚动是解决这些缩放问题的主要技术。虚拟滚动通过提供大小适当的滚动条,给人以非常大的列表的印象,并且能够浏览列表,而无需应用将整个列表保存在内存中或在页面上呈现。

在 Angular 中,虚拟滚动由 Component Dev Kit (CDK) 提供。通过修改迭代列表的方式并提供一些额外的配置参数,CDK 的虚拟滚动功能将自动管理列表的虚拟呈现,从而提升页面性能和响应能力。

系统只会渲染能显示在屏幕上的部分项(以及一个小缓冲区),而不是一次渲染整个列表。当用户导航时,系统会计算并呈现一组新的项子集,并根据需要重复使用现有 DOM。

本文的其余部分将详细介绍如何设置基本虚拟滚动。您可以在以下示例应用中查看完整的工作示例:

设置虚拟滚动

首先,请确保您已使用自己偏好的软件包管理器安装 @angular/cdk。如需使用 npm 安装它,请在终端中运行以下命令:

npm install --save @angular/cdk

ScrollingModule 添加到您的应用

安装 CDK 后,从 @angular/cdk/scrolling 软件包导入用于处理虚拟滚动的 ScrollingModule。然后将其添加到模块的 imports 数组中:

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);
}

当浏览器渲染应用时,它必须渲染 10 万个单独的 <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 的虚拟滚动功能远远超出了这个基本示例。在示例应用中,整个列表都在内存中,但对于更复杂的应用,可以按需提取列表。如需详细了解 ScrollingModulecdkVirtualOf 指令的其他功能,请参阅 CDK 文档中关于 Scrolling 的内容。

主打图片由 Unsplash 用户 Mr Cup / Fabien Barral 提供。