CdkTable
是一个非自用的、可定制的数据表格格,它包含一个完全模板化的 API、动态列和一个可访问的 DOM 结构。这个组件充当了核心,任何人都可以在此基础上构建自己定制的数据表格格。
表格提供了一个基础,可以在这个基础上构建其它特性,比如排序和分页。由于它不强制要求这些琐事,因此开发人员可以完全控制与该表格有关的交互模式。
有关 Material Design 风格的表格,请参阅
MatTable
文档,它建立在 CDK 数据表格之上。
编写数据表格模板的第一步是定义列。列的定义是通过带有 cdkColumnDef
指令的 <ng-container>
来指定的,并赋予该列一个名字。每个列定义都可以包含一个表头单元格模板(cdkHeaderCellDef
),一个数据单元格模板(cdkCellDef
)和一个表尾单元格模板(cdkFooterCellDef
)。
<ng-container cdkColumnDef="username">
<th cdk-header-cell *cdkHeaderCellDef> User name </th>
<td cdk-cell *cdkCellDef="let row"> {{row.a}} </td>
<td cdk-footer-cell *cdkFooterCellDef> User name </td>
</ng-container>
列定义的集合表示可供渲染的列。要渲染的特定列及其顺序可以在本行中指定(稍后讲)。
注意,cdkCellDef
导出了本行的上下文,以便在单元格模板中引用本行的数据。该指令还导出了一些与 ngFor
相同的属性(index,even,odd,first,last)。
下一步是定义表格的表头行(cdkHeaderRowDef
)、数据行(cdkRowDef
)和表尾行(cdkFooterRowDef
)。注意,它们都是可选的,具体取决于你要渲染的行类型(例如,如果你不需要一个表尾行,那就不要添加它的定义)。
<tr cdk-header-row *cdkHeaderRowDef="['username', 'age', 'title']"></tr>
<tr cdk-row *cdkRowDef="let row; columns: ['username', 'age', 'title']"></tr>
<tr cdk-footer-row *cdkFooterRowDef="['username', 'age', 'title']"></tr>
这些行模板通过赋值给 cdkColumnDef
的名字来接受要渲染的指定列。
cdkRowDef
也会导出行的上下文,它可以用在这个行元素的事件和属性绑定上。任何放在标题行或数据行模板中的内容都会被忽略,因为该行渲染的内容来自上面描述的单元格模板。
<table cdk-table [dataSource]="dataSource">
<!-- User name Definition -->
<ng-container cdkColumnDef="username">
<th cdk-header-cell *cdkHeaderCellDef> User name </th>
<td cdk-cell *cdkCellDef="let row"> {{row.username}} </td>
</ng-container>
<!-- Age Definition -->
<ng-container cdkColumnDef="age">
<th cdk-header-cell *cdkHeaderCellDef> Age </th>
<td cdk-cell *cdkCellDef="let row"> {{row.age}} </td>
</ng-container>
<!-- Title Definition -->
<ng-container cdkColumnDef="title">
<th cdk-header-cell *cdkHeaderCellDef> Title </th>
<td cdk-cell *cdkCellDef="let row"> {{row.title}} </td>
</ng-container>
<!-- Header and Row Declarations -->
<tr cdk-header-row *cdkHeaderRowDef="['username', 'age', 'title']"></tr>
<tr cdk-row *cdkRowDef="let row; columns: ['username', 'age', 'title']"></tr>
</table>
本行给出的这些列决定要渲染哪些单元格以及按什么顺序。因此,可以通过绑定来设置列,以支持动态更改运行时要显示的列。
<tr cdk-row *cdkRowDef="let row; columns: myDisplayedColumns"></tr>
不需要包括显示模板中定义的所有列,也不需要使用与定义时相同的顺序。例如,要显示一个只包含 age
和 username
的表格,那么行和头的定义就写成:
<tr cdk-row *cdkRowDef="let row; columns: ['age', 'username']"></tr>
事件和属性绑定可以直接添加到 row 元素上。
<tr cdk-header-row *cdkHeaderRowDef="['age', 'username']"
(click)="handleHeaderRowClick(row)">
</tr>
<tr cdk-row *cdkRowDef="let row; columns: ['age', 'username']"
[class.can-vote]="row.age >= 18"
(click)="handleRowClick(row)">
</tr>
每个表头和数据行中的单元格都会被提供一个包含其列的 CSS 类。例如,name
列中显示的单元格将被赋予 cdk-column-name
类。这样就可以让列的样式在表头和数据行之间保持一致。
由于列的名字可以是任意字符串,所以它可能无法直接用在 CSS 类中(例如 *nameColumn!
)。此时,这些特殊字符将替换成 -
字符。例如,*nameColumn!
列中的单元格容器将会带有 cdk-column--nameColumn-
类。
数据会通过 DataSource
提供给表格。当表格接收数据源时,它会调用 DataSource 的 connect()
方法,该方法返回一个发出数组型数据的可观察对象。每当数据源向此流中发出数据时,该表格都会重新渲染一次。
由于数据源提供了这个流,因此它要负责触发表格更新。这可能由任何事情触发:websocket 连接、用户交互、模型更新、基于时间间隔等。最常见的是,这些更新将由用户交互(如排序和分页)触发。
fixedLayout
CDK 表会应用粘滞样式之前要先测量粘滞元素的尺寸。由于原生表格会根据每个单元格内的内容计算出列宽,因此没当基础数据发生变化时就会重新检查这些尺寸。
启用 fixedLayout
将强制统一列宽,这样表格就可以在计算粘滞样式时可靠地缓存和复用它们。这可以减少大型原生表格的渲染延迟。
<table cdk-table [dataSource]="dataSource" fixedLayout>
trackBy
要想提高性能,可以在表格中提供一个类似于 Angular 的 ngFor
trackBy
指令。这会告诉表格要如何唯一地标识这些行,用以跟踪每次更新后数据的变化情况。
<table cdk-table [dataSource]="dataSource" [trackBy]="myTrackById">
recycleRows
默认情况下, CdkTable
会为每一行创建和销毁一个内部 Angular 视图。这允许这些行参与动画并使用 cdkRowDefWhen
在不同的行模板之间切换。如果你不需要这些功能,可以通过指定 recycleRows
来指示表格缓存和回收这些行。
<table cdk-table [dataSource]="dataSource" recycleRows>
CDK 表格并不要求你使用原生 HTML 表格。如果你想完全控制表格的样式,遵循不使用原生表格元素标签的替代模板方法可能会更容易些。
这种替代方法用 CDK 的表格指令选择器替换了原生的表格元素标签。比如,<table cdk-table>
变为 <cdk-table>
、<tr cdk-row
> 变为 <cdk-row>
。下面的例子展示了改用这个替代模板实现前一个例子:
<cdk-table [dataSource]="dataSource">
<!-- User name Definition -->
<ng-container cdkColumnDef="username">
<cdk-header-cell *cdkHeaderCellDef> User name </cdk-header-cell>
<cdk-cell *cdkCellDef="let row"> {{row.username}} </cdk-cell>
</ng-container>
<!-- Age Definition -->
<ng-container cdkColumnDef="age">
<cdk-header-cell *cdkHeaderCellDef> Age </cdk-header-cell>
<cdk-cell *cdkCellDef="let row"> {{row.age}} </cdk-cell>
</ng-container>
<!-- Title Definition -->
<ng-container cdkColumnDef="title">
<cdk-header-cell *cdkHeaderCellDef> Title </cdk-header-cell>
<cdk-cell *cdkCellDef="let row"> {{row.title}} </cdk-cell>
</ng-container>
<!-- Header and Row Declarations -->
<cdk-header-row *cdkHeaderRowDef="['username', 'age', 'title']"></cdk-header-row>
<cdk-row *cdkRowDef="let row; columns: ['username', 'age', 'title']"></cdk-row>
</cdk-table>
有关如何将此结构渲染为表格的示例,请参阅 <mat-table>
的文档,其中包括此方法所需的样式支持。