יצירת וירטואליות של רשימות גדולות באמצעות CDK של 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> נפרדים. הפתרון הזה יכול להתאים לצמתים פשוטים של טקסט, אבל כל מורכבות בתבנית החוזרת לא תתאים להתאמה לעומס, וכל פונקציות ה-event listener יוכפלו באופן משמעותי.

כדי להוסיף גלילה וירטואלית ולהימנע מהבעיות האלה, צריך ליצור שדה ראייה על ידי גיבוב הרשימה ברכיב <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 רגיל. בנוסף, צריך לתת ל-viewport רמז לגבי התוכן שלו על ידי ציון הערך 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.

התמונה הראשית (Hero) של Mr Cup / Fabien Barral ב-Unsplash.