使用 Angular CDK 虚拟化大型列表

通过实现虚拟滚动,使大型列表更具响应性。

滚动列表是当今最常见的 UI 模式之一,无论是浏览您最喜欢的社交媒体网站上无限滚动的 feed,还是浏览企业仪表板。当滚动列表变得非常长(成百上千甚至成千上万个项目)时,应用程序性能可能会受到影响。

大型列表加载速度可能很慢,因为应用程序必须预先加载和渲染所有数据。它们渲染和导航速度也可能很慢,因为列表中的每个项目都可能包含丰富的数据、媒体和功能。

用户在加载或滚动页面时可能会遇到问题,从而导致沮丧和页面放弃。

在 Angular 中使用组件开发工具包进行虚拟滚动

虚拟滚动是用于解决这些规模问题的主要技术。虚拟滚动通过提供适当大小的滚动条,以及在无需应用程序将整个列表保存在内存中或在页面上渲染的情况下导航列表的能力,给人一种非常大的列表的印象。

在 Angular 中,虚拟滚动由 组件开发工具包 (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);
}

当浏览器渲染应用时,它必须渲染 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 的虚拟滚动功能远不止此基本示例。在示例应用中,整个列表都在内存中,但对于更复杂的应用程序,可以按需获取列表。您可以通过阅读 CDK 文档中关于 Scrolling 的内容,了解有关 ScrollingModulecdkVirtualOf 指令的其他功能的更多信息。

英雄图片由 Mr Cup / Fabien Barral 在 Unsplash 上提供。