📊 DataTable 表格组件核心解析
DevUI DataTable 是一个基于 Angular 的企业级表格组件 ,支持数据展示、排序、过滤、编辑、树形结构、虚拟滚动 等多种高级功能,适用于复杂的中后台管理系统。

1. 安装与引入
在你的 Angular 项目(要求 ^18.0.0)中,需要先安装并导入 DataTable 模块。
typescript
// app.module.ts 或相应的功能模块
import { NgModule } from '@angular/core';
import { DataTableModule } from 'ng-devui/data-table';
@NgModule({
imports: [
// ... 其他模块
DataTableModule
],
// ...
})
export class AppModule { }
2. 基础使用与核心参数
一个最简单的表格只需要 dataSource 数据源和列定义即可工作。

html
<!-- your-component.component.html -->
<d-data-table #datatable [dataSource]="basicDataSource" [scrollable]="true" [tableOverflowType]="'overlay'">
<d-column field="$index" header="#" [width]="'50px'"></d-column>
<d-column
*ngFor="let colOption of dataTableOptions.columns"
[field]="colOption.field"
[header]="colOption.header"
[fieldType]="colOption.fieldType"
[width]="'150px'"
>
</d-column>
</d-data-table>
typescript
import { Component,OnInit } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { CommonModule } from '@angular/common';
import { PanelModule } from 'ng-devui';
import { DataTableModule } from 'ng-devui/data-table';
import { TableWidthConfig } from 'ng-devui/data-table';
import { originSource, SourceType } from './mockdata';
// import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
@Component({
selector: 'app-root',
standalone: true,
imports: [CommonModule,RouterOutlet,PanelModule,DataTableModule],
templateUrl: './app.component.html',
styleUrl: './app.component.less'
})
export class AppComponent implements OnInit {
title = 'devuidemo';
// 基础数据源
basicDataSource: Array<SourceType> = JSON.parse(JSON.stringify(originSource.slice(0, 6)));
dataTableOptions = {
columns: [
{
field: 'firstName',
header: 'First Name',
fieldType: 'text',
order: 1
},
{
field: 'lastName',
header: 'Last Name',
fieldType: 'text',
order: 2
},
{
field: 'gender',
header: 'Gender',
fieldType: 'text',
order: 3
},
{
field: 'dob',
header: 'Date of birth',
fieldType: 'date',
order: 4
}
]
};
ngOnInit() {
}
}
🔑 核心配置参数速查
下表汇总了开发中最常用的一些参数,你可以根据需求快速查阅:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
dataSource |
any[] |
-- | 必选,表格的数据源 |
size |
`'sm' | 'md' | 'lg'`等 |
checkable |
boolean |
-- | 是否启用行选择(显示复选框) |
fixHeader |
boolean |
false |
是否固定表头(配合 maxHeight 使用) |
maxHeight |
string |
-- | 设置表格最大高度,超出则内部滚动 |
scrollable |
boolean |
-- | 表格内容溢出容器时是否允许滚动 |
striped |
boolean |
false |
是否显示斑马纹(交替行背景色) |
borderType |
`'' | 'bordered'`等 | '' |
3. 典型功能场景与代码示例
场景一:表头固定的交互表格
此场景常用于需要对行数据进行批量操作的列表。

html
<d-data-table
[dataSource]="maxHeightDataSource"
[fixHeader]="true"
[tableOverflowType]="'overlay'"
tableHeight="360px"
[containFixHeaderHeight]="true"
[scrollable]="true"
>
<thead dTableHead>
<tr dTableRow>
<th dHeadCell *ngFor="let colOption of dataTableOptions.columns">{{ colOption.header }}</th>
</tr>
</thead>
<tbody dTableBody>
<ng-template let-rowItem="rowItem" let-rowIndex="rowIndex">
<tr dTableRow>
<td dTableCell *ngFor="let colOption of dataTableOptions.columns">
{{ colOption.fieldType === 'date' ? (rowItem[colOption.field] | i18nDate : 'short' : false) : rowItem[colOption.field] }}
</td>
</tr>
</ng-template>
</tbody>
</d-data-table>
typescript
import {
ChangeDetectionStrategy,
Component,
OnInit
} from '@angular/core';
import { originSource, SourceType } from '../mock-data';
@Component({
selector: 'd-datatable-demo-maxheight',
changeDetection: ChangeDetectionStrategy.OnPush,
templateUrl: './data-table-demo-maxheight.component.html'
})
export class DatatableDemoMaxheightComponent implements OnInit {
dataTableOptions = {
columns: [
{
field: 'firstName',
header: 'First Name',
fieldType: 'text',
sortable: true,
},
{
field: 'lastName',
header: 'Last Name',
fieldType: 'text',
sortable: true,
},
{
field: 'gender',
header: 'gender',
fieldType: 'text',
sortable: true,
},
{
field: 'dob',
header: 'Date of birth',
fieldType: 'date',
sortable: true,
}
]
};
maxHeightDataSource: Array<SourceType> = JSON.parse(JSON.stringify(originSource.slice()));
ngOnInit() {
}
}
场景二:支持可编辑单元格的表格
单元格编辑是表格编辑时候的常用功能。

html
<d-data-table #dataTable size="sm" [dataSource]="basicDataSource" [tableOverflowType]="'overlay'" [scrollable]="true">
<thead dTableHead>
<tr dTableRow>
<th dHeadCell>Last Name</th>
<th dHeadCell>Date of birth</th>
<th dHeadCell>Age</th>
<th dHeadCell>Gender</th>
</tr>
</thead>
<tbody dTableBody>
<ng-template let-rowItem="rowItem" let-rowIndex="rowIndex">
<tr dTableRow>
<td
dTableCell
[editable]="true"
[editableTip]="editableTip"
[(editing)]="rowItem['nameEdit']"
[rowItem]="rowItem"
[field]="'lastName'"
[beforeEditStart]="beforeEditStart"
[beforeEditEnd]="beforeEditEnd"
>
<span *ngIf="!rowItem['nameEdit']">{{ rowItem?.lastName }}</span>
<div *ngIf="rowItem['nameEdit']" class="edit-padding-fix">
<!-- 引入dCommonsModule的autofocus -->
<input
[dAutoFocus]="true"
class="devui-form-control"
name="lastname"
[(ngModel)]="rowItem.lastName"
[attr.maxlength]="100"
[attr.minlength]="3"
/>
</div>
</td>
<td dTableCell [editable]="true" [(editing)]="rowItem['dateEdit']">
<span *ngIf="!rowItem['dateEdit']">{{ rowItem?.dob | i18nDate : 'short' : false }}</span>
<form *ngIf="rowItem['dateEdit']" class="form-inline edit-padding-fix">
<div class="devui-form-group">
<div class="devui-input-group devui-dropdown-origin">
<input
class="devui-form-control search"
name="date"
[(ngModel)]="rowItem.dob"
dDatepicker
appendToBody
#datePicker="datepicker"
[autoOpen]="true"
(ngModelChange)="onEditEnd(rowItem, 'dateEdit')"
/>
<div class="devui-input-group-addon" (click)="datePicker.toggle()">
<i class="icon icon-calendar"></i>
</div>
</div>
</div>
</form>
</td>
<td dTableCell [editable]="true" [(editing)]="rowItem['ageEdit']">
<span *ngIf="!rowItem['ageEdit']">{{ rowItem?.age }}</span>
<div *ngIf="rowItem['ageEdit']" class="edit-padding-fix">
<d-input-number [autoFocus]="true" [(ngModel)]="rowItem.age"></d-input-number>
</div>
</td>
<td dTableCell [editable]="true" [(editing)]="rowItem['genderEdit']">
<span *ngIf="!rowItem['genderEdit']">{{ rowItem?.gender?.label }}</span>
<div *ngIf="rowItem['genderEdit']" class="customized-editor edit-padding-fix">
<d-select
[options]="genderSource"
[isSearch]="true"
[filterKey]="'label'"
[autoFocus]="true"
[toggleOnFocus]="true"
[appendToBody]="true"
[(ngModel)]="rowItem.gender"
(ngModelChange)="onEditEnd(rowItem, 'genderEdit')"
>
<ng-template let-option="option" let-filterKey="filterKey"> gender:{{ option[filterKey] }} </ng-template>
</d-select>
</div>
</td>
</tr>
</ng-template>
</tbody>
</d-data-table>
typescript
import { Component, OnInit } from '@angular/core';
import { EditableTip } from 'ng-devui/data-table';
import { cloneDeep } from 'lodash-es';
import { editableOriginSource, genderSource } from '../mock-data';
@Component({
selector: 'd-editable',
templateUrl: './data-table-demo-editable.component.html'
})
export class DatatableDemoEditableComponent implements OnInit {
genderSource = genderSource;
basicDataSource = cloneDeep(editableOriginSource.slice(0, 6));
editableTip = EditableTip.hover;
nameEditing: boolean;
ngOnInit() {
}
onEditEnd(rowItem, field) {
rowItem[field] = false;
}
beforeEditStart = (rowItem, field) => {
return true;
};
beforeEditEnd = (rowItem, field) => {
console.log('beforeEditEnd');
if (rowItem && rowItem[field].length < 3) {
return false;
} else {
return true;
}
};
}
场景三:可展开的树形表格
用于展示具有层级关系的数据结构。

html
<d-button class="demo-margin" (btnClick)="setUnCheckableRelation('downward')">选中父不再选中子</d-button>
<d-button bsStyle="common" class="demo-margin" (btnClick)="setUnCheckableRelation('upward')">选中子不再选中父</d-button>
<d-button bsStyle="common" class="demo-margin" (btnClick)="toggleIcon()">使用自定义展开/收起图标</d-button>
<d-button bsStyle="common" class="demo-margin" (btnClick)="expandAll()">展开全部表格</d-button>
<d-data-table
[dataSource]="basicDataSource"
[tableWidthConfig]="tableWidthConfig"
[checkableRelation]="checkableRelation"
[loadChildrenTable]="loadChildrenTable"
[loadAllChildrenTable]="loadAllChildrenTable"
[scrollable]="true"
[tableOverflowType]="'overlay'"
>
<thead dTableHead [checkable]="true">
<tr dTableRow>
<th dHeadCell [nestedColumn]="true" [iconFoldTable]="iconParentOpen" [iconUnFoldTable]="iconParentClose">title</th>
<th dHeadCell>name</th>
<th dHeadCell>status</th>
<th dHeadCell>date</th>
</tr>
</thead>
<tbody dTableBody>
<ng-template let-rowItem="rowItem" let-rowIndex="rowIndex" let-nestedLayer="nestedLayer" let-nestedIndex="nestedIndex">
<tr dTableRow [ngClass]="{ 'table-row-selected': rowItem.$checked }">
<td dTableCell class="devui-checkable-cell">
<d-checkbox
[ngModelOptions]="{ standalone: true }"
[ngModel]="rowItem.$checked"
[halfchecked]="rowItem.$halfChecked"
[disabled]="rowItem.$checkDisabled"
(ngModelChange)="onRowCheckChange($event, rowIndex, nestedIndex, rowItem)"
dTooltip
[content]="rowItem.$checkBoxTips"
[position]="['top', 'right', 'bottom', 'left']"
>
</d-checkbox>
</td>
<td
dTableCell
[nestedColumn]="true"
[nestedColumnIndent]="20"
[rowItem]="rowItem"
[nestedLayer]="nestedLayer"
[iconFoldTable]="iconParentOpen"
[iconUnFoldTable]="iconParentClose"
(toggleChildTableEvent)="onChildTableToggle($event, rowItem)"
>
{{ rowItem['title'] }}
</td>
<td dTableCell>{{ rowItem['lastName'] }}</td>
<td dTableCell>{{ rowItem['status'] }}</td>
<td dTableCell>{{ rowItem['dob'] | i18nDate : 'short' : false }}</td>
</tr>
</ng-template>
</tbody>
</d-data-table>
typescript
import {
Component,
OnInit,
ViewChild
} from '@angular/core';
import {
CheckableRelation,
DataTableComponent,
TableWidthConfig
} from 'ng-devui/data-table';
import {
SourceType,
treeDataSource
} from '../mock-data';
@Component({
selector: 'd-tree-data',
templateUrl: './tree-data.component.html',
styles: ['.demo-margin { margin: 5px 5px 0 0;}']
})
export class TreeDataComponent implements OnInit {
iconParentOpen: string;
iconParentClose: string;
basicDataSource: Array<SourceType> = JSON.parse(JSON.stringify(treeDataSource.slice(0, 6)));
checkableRelation: CheckableRelation = {downward: true, upward: true};
@ViewChild(DataTableComponent, { static: true }) datatable: DataTableComponent;
tableWidthConfig: TableWidthConfig[] = [
{
field: 'checkbox',
width: '4%'
},
{
field: 'title',
width: '36%'
},
{
field: 'lastName',
width: '20%'
},
{
field: 'status',
width: '20%'
},
{
field: 'dob',
width: '20%'
}
];
ngOnInit() {
this.basicDataSource[0].$isChildTableOpen = true;
}
onChildTableToggle(status, rowItem) {
this.datatable.setRowChildToggleStatus(rowItem, status);
}
loadChildrenTable = (rowItem) => {
return new Promise((resolve) => {
setTimeout(() => {
if (rowItem.title === 'table title1') {
if (rowItem.children && rowItem.children.length === 0) {
rowItem.children.push({
title: 'table title11',
lastName: 'Mark',
status: 'done',
dob: new Date(1989, 1, 1),
startDate: new Date(2020, 1, 4),
endDate: new Date(2020, 1, 8)
});
}
}
resolve(rowItem);
}, 500);
});
};
loadAllChildrenTable = () => {
return new Promise((resolve) => {
setTimeout(() => {
this.basicDataSource[0].children[0].children[1].children[0].children = [];
this.basicDataSource[0].children[0].children[1].children[0].children.push({
title: 'table title01211',
lastName: 'Mark',
status: 'done',
dob: new Date(1989, 1, 1),
},
{
title: 'table title01212',
lastName: 'Mark',
status: 'done',
dob: new Date(1991, 3, 1)
});
resolve(undefined);
}, 500);
});
};
setUnCheckableRelation(type) {
if (type === 'upward') {
this.checkableRelation.upward = false;
} else {
this.checkableRelation.downward = false;
}
}
toggleIcon() {
this.iconParentOpen = '<span class="icon icon-chevron-right"></span>';
this.iconParentClose = '<span class="icon icon-chevron-down"></span>';
}
onRowCheckChange(checked, rowIndex, nestedIndex, rowItem) {
rowItem.$checked = checked;
rowItem.$halfChecked = false;
this.datatable.setRowCheckStatus({
rowIndex: rowIndex,
nestedIndex: nestedIndex,
rowItem: rowItem,
checked: checked
});
}
expandAll() {
this.datatable.setTableChildrenToggleStatus(true);
}
}
4. 开发实践与建议
- 性能优化 :当渲染超大数据集 (如数千行)时,务必开启
virtualScroll(虚拟滚动) 功能,它只会渲染可视区域内的 DOM 元素,能极大提升性能。 - 状态管理 :如果表格与复杂状态关联(如多步骤表单、全局状态),建议将
dataSource与前端状态管理(如 NgRx、Akita)结合,而不是依赖组件内部状态。 - 列配置 :对于动态列的需求,可以创建一个
Column[]配置数组,配合*ngFor在模板中动态生成<d-table-column>,这样更加灵活。 - 数据更新 :修改
dataSource数组引用(例如this.dataSource = [...newData])会触发表格完整刷新 。若只想更新某一行,可以修改该行对象的属性并配合ChangeDetectorRef的detectChanges()方法。
参考资料:
MateChat:https://gitcode.com/DevCloudFE/MateChat
MateChat官网:https://matechat.gitcode.com
DevUI官网:https://devui.design/home