65.9K
CodeProject 正在变化。 阅读更多。
Home

Angular 中的虚拟列表

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0投票)

2020 年 2 月 24 日

CPOL

1分钟阅读

viewsIcon

8074

创建包含大量数据的列表,而不会使 DOM 变得臃肿

引言

Angular 中的虚拟列表有助于将大量数据加载到视图中,并保持 DOM 的一致性。 这样可以帮助提高 UI 的性能。

背景

当您在 Angular UI 上显示大量数据列表时,您需要实现分页,这需要向服务器发送请求以获取每一页(例如,每页 10 条数据),否则大量数据可能会导致视图性能问题。

Using the Code

该代码使用了虚拟列表的 npm 包。

//install virtuallist npm using command "npm i angular-virtual-list"
//in app.module.ts import following
import { VirtualListModule } from 'angular-virtual-list';

import { Component, OnInit } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import { ChangeEvent } from 'angular-virtual-list';
//model class
export class UserModel {
  id: number;
  name?: string;
  contact?: string;
  address?:string;
}

@Component({
  selector: 'app-virtuallist',
  templateUrl: './virtuallist.component.html',
  styleUrls: ['./virtuallist.component.scss']
})

export class VirtuallistComponent implements OnInit {
  public items: Array<UserModel>=[];
  public scrollList: Array<UserModel>=[];
//source for the virtual list
  protected items$ = new BehaviorSubject<UserModel[]>(null);
  protected buffer: UserModel[] = [];
  protected loading: boolean;
// display starting record currently loaded in viewport
  startingItem:number;
//display end record currently loaded in viewport
  enditem:number;
  constructor() {
    this.setItem();
  }

  ngOnInit() {
  }
  protected fetchMore(event: ChangeEvent) {
    this.startingItem=event.start+1;
    this.enditem= event.end;
    if (event.end == this.buffer.length) 
    return;
}

  public setItem() {
    for (var i = 0; i <1000000; i++) {
      var item = new UserModel()
      item.id = i+1;
      item.name = "Name " + (i+1).toString();
      item.contact="+1 650-253-0000";
      item.address=(1600+i+1).toString()+" Amphitheatre Pkwy, 
                   Mountain View, CA 94043, United States";
      this.items.push(item);
    }
    this.items$.next(this.items)
    console.log(this.scrollList)
  }
}

HTML 视图如下所示

<h2>Total Record Count: {{items.length}}</h2>
<h2 *ngIf="startingItem">{{startingItem}} to {{enditem}} of {{items.length}} are loaded</h2>
  <div class="table-like">
    <div class="table-head">
      <span style="margin-left: 2px; text-align: center;">Id</span>
      <span style="margin-left: 50px; text-align: center;">Name</span> 
      <span style="margin-left: 60px; text-align: center;">Contact Number</span>
      <span style="margin-left: 200px;">Address</span> 
    </div>
  <virtual-list
  [source$]="items$"
  (update)="scrollList = $event"
  (end)="fetchMore($event)" height=400>
  
  <div *ngFor="let item of scrollList" style="display: table-row;">
   <span style="display: table-cell; padding: 3px 0 0 2px; text-align: center;">
       {{item.id}}</span>
   <span style="display: table-cell; padding-left: 36px;text-align: center;">
       {{item?.name}}</span> 
   <span style="display: table-cell; padding-left: 36px;">{{item?.contact}}</span>
   <span style="display: table-cell; padding-left: 36px;">{{item?.address}}</span> 
  </div>

</virtual-list>
</div>

CSS 如下

.table-like{
    border: 1px solid #9173ff;
    width: 900px;
}

.table-head{
    color: #fff;
    background-color: #6940ff;
    border-bottom: 1px solid #9173ff;
}

每当用户滚动列表时,它将显示固定数量的行,以保持 DOM 的一致性,例如,如果我的服务发送包含 100 万个元素的数组,并且虚拟列表的高度为 500 像素,那么它将一次显示大约 10-14 行数据,并且在滚动时,这些行将更改为下一个或前一个元素。

因此,DOM 中始终只有 10 到 14 行,这保持了性能的稳定。

关注点

您可以在我的 GitHub 仓库中找到完整的代码:https://github.com/cruse07/AngularTest/

查看 virtuallist 组件。

历史

  • 2020 年 2 月 24 日:初始版本
© . All rights reserved.