使用 Angular CDK 將大型清單虛擬化

實作虛擬捲動功能,讓大型清單的回應更加靈敏。

Stephen Fluin
Stephen Fluin

捲動清單是目前最常見的 UI 模式之一,無論是在喜愛的社群媒體網站上瀏覽無限捲動的動態消息,還是瀏覽企業資訊主頁,都能使用。如果捲動清單變得很長 (數百個、數千個或數十萬個項目),應用程式效能可能會受到影響。

大型清單的載入速度可能會變慢,因為應用程式必須預先載入並轉譯所有資料。轉譯和瀏覽速度也很慢,因為清單中的每個項目都包含多媒體資料、媒體和功能。

使用者載入或捲動網頁時可能會遇到問題,因而造成不便,甚至放棄瀏覽網頁。

透過元件開發套件在 Angular 進行虛擬捲動

虛擬捲動功能是解決這些縮放問題的主要技術。虛擬捲動功能具有調整尺寸的捲軸,能夠呈現非常龐大的清單,而且使用者可以瀏覽清單,而且應用程式不必將整個清單儲存在記憶體中,也不需在頁面上算繪清單內容。

在 Angular 中,虛擬捲動功能是由元件開發套件 (CDK) 提供。透過修改疊代清單的方式,並且提供幾個額外的設定參數,CDK 的虛擬捲動功能就會自動管理清單的虛擬顯示方式,進而改善網頁效能和回應速度。

系統只會顯示符合螢幕大小的項目子集 (加上小型緩衝區),而非一次顯示整個清單。當使用者瀏覽時,系統會計算並顯示一個新的項目子集,並視需要重複使用現有的 DOM。

本文的其餘部分將逐步說明如何設定基本的虛擬捲動功能。您可以在此範例應用程式中查看完整的實際範例:

設定虛擬捲動

首先,確認您已使用偏好的套件管理員安裝 @angular/cdk。如要透過 npm 安裝 npm,請在終端機中執行下列指令:

npm install --save @angular/cdk

將「ScrollingModule」新增至應用程式

安裝 CDK 後,請從 @angular/cdk/scrolling 套件匯入 ScrollingModule,以處理虛擬捲動。然後將其新增至模組的匯入陣列:

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 指令,請參閱 CDK 說明文件中的 Scrolling

主頁橫幅由 Mr Cup / Fabien Barral 在 Unsplash 上提供。