Angular 8 带来了非常酷的功能来实现虚拟滚动。他们在此处提供了有关其用法的示例。虽然,它真的很难用 mat-table 实现。
我一直致力于在 mat-table 上实现虚拟滚动,发现我们需要有自己的自定义数据源。我通过实现DataSource
类创建了新的数据源,但我发现,由于自定义数据源,我失去了排序和其他功能。
app.component.html
<cdk-virtual-scroll-viewport class="example-viewport">
<table class="table" mat-table #table matSort [dataSource]="dataSource" [multiTemplateDataRows]="true">
<ng-container matColumnDef="id">
<th mat-header-cell *matHeaderCellDef mat-sort-header> id </th>
<td mat-cell *matCellDef="let element"> {{element.id}} </td>
</ng-container>
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Name</th>
<td mat-cell *matCellDef="let element"> {{element.name}} </td>
</ng-container>
<ng-container matColumnDef="age">
<th mat-header-cell *matHeaderCellDef> Age</th>
<td mat-cell *matCellDef="let element"> {{element.age}} </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr>
<!-- cdkVirtualScrollViewport uses transform: translateY to correct for all elements that are removed.
We will use a plcaholder row in the table instead because the translate causes problems with the sticky header -->
<tr [style.height.px]="placeholderHeight" mat-row *matRowDef="let row; let index = index; columns: []; when: placeholderWhen"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
</table>
</cdk-virtual-scroll-viewport>
app.component.ts
import { Component, OnInit, ViewChild, AfterViewInit } from "@angular/core";
import {
CdkVirtualScrollViewport,
FixedSizeVirtualScrollStrategy,
VIRTUAL_SCROLL_STRATEGY
} from "@angular/cdk/scrolling";
import { CollectionViewer } from "@angular/cdk/collections";
import { MatSort } from "@angular/material";
// import { GridTableDataSource } from './gridTable.datasource'
import { GridTableDataSource } from "./gridTableM.datasource";
const ROW_HEIGHT = 48;
/**
* Virtual Scroll Strategy
*/
export class CustomVirtualScrollStrategy extends FixedSizeVirtualScrollStrategy {
constructor() {
super(ROW_HEIGHT, 1000, 2000);
}
attach(viewport: CdkVirtualScrollViewport): void {
this.onDataLengthChanged();
}
}
@Component({
selector: "my-app",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"],
providers: [
{ provide: VIRTUAL_SCROLL_STRATEGY, useClass: CustomVirtualScrollStrategy }
]
})
export class AppComponent implements OnInit, AfterViewInit {
placeholderHeight = 0;
displayedColumns: string[] = ["id", "name", "age"];
dataSource: GridTableDataSource<any>;
rows = Array(200)
.fill(0)
.map((x, i) => {
return { name: "name" + i, id: i, age: 27 };
});
itemSize = 48;
@ViewChild(CdkVirtualScrollViewport, { static: true })
viewport: CdkVirtualScrollViewport;
@ViewChild(MatSort, { static: false }) sort: MatSort;
constructor() {}
ngOnInit() {
this.dataSource = new GridTableDataSource(
this.rows,
this.viewport,
this.itemSize
);
this.dataSource.offsetChange.subscribe(offset => {
this.placeholderHeight = offset;
});
this.dataSource.data = this.rows;
// debugger;
// this.dataSource.sort = this.sort; // this.sort is null here
}
ngAfterViewInit() {
debugger;
this.dataSource.sort = this.sort; // this.sort is null here as well
}
placeholderWhen(index: number, _: any) {
return index == 0;
}
}
为了实现排序和其他功能,我只是从MatTableDataSource复制了代码。但不知何故,this.sort
在任何方法中总是为空。我找不到原因。谁能解释这种行为?
这是可以玩的stackblitz 。