自 Extensions 组件库发布以来,Data Grid 成为了使用及咨询最多的组件。最开始 Data Grid 的设计很是简陋,通过一番重构,组件质量有了质的提高。
Extensions 组件库: https://github.com/ng-matero/extensions
Data Grid 示例: https://ng-matero.github.io/extensions/data-grid
距离 Extensions Data Grid 重构已通过去了两个多月,因工做忙碌而迟迟没有介绍 Extensions Data Grid 的细节。这几天又重构了一下官网示例,目前的 API 文档放在了 gitbook 上,暂时尚未和官网整合,国内访问会比较慢。本文会介绍 Data Grid 的使用方法及比较好的一些功能实现。说点题外话,开发一款插件最大的难度不在于功能的实现,而在于如何去设计插件。html
Data Grid 本质上就是经过 数据
+列定义
+配置项
来渲染表格的插件。这比写一堆 DOM 结构要简洁不少,能够说是 CRUD 业务中的大杀器之一。目前市面上功能最全的 Data Grid 是 ag-grid,不少组件库也有本身的 Data Grid 实现,好比 Ignite UI,Kendo UI。可是市面上这些优秀的插件基本都要收费,另外就是遇到变态需求时,第三方插件的功能定制会遇到不少问题,这也是我自研 Data Grid 的初衷。前端
Angular Material 对于 table 的封装已经足够灵活,可是模板的定义依然很繁琐,也缺乏不少刚需功能。Extensions Data Grid 几乎整合了 Angular Material 表格的全部功能,同时又增长了不少实用功能。git
Extensions Data Grid 的功能实现参考了 ag-grid 以及其它插件,重构时对变量及参数命名进行了很细致的考究。目前 Extensions Data Grid 已经实现的功能以下:github
因文章篇幅有限,本文主要介绍一些重点功能,其它功能能够参考官网示例。后端
官网示例: Basic
定义组件参数app
<mtx-grid [data]="list" [columns]="columns"> </mtx-grid>
定义数据及列async
export class AppComponent { columns: MtxGridColumn[] = [ { header: 'Name', field: 'name' }, { header: 'Weight', field: 'weight' }, { header: 'Gender', field: 'gender' }, { header: 'Mobile', field: 'mobile' }, { header: 'City', field: 'city' }, ]; list = EXAMPLE_DATA; }
补充介绍一下,市面上 Data Grid 定义列的方式主要有两种:ide
一、JS 定义,好比 ag-gridui
var gridOptions = { // define 3 columns columnDefs: [ { headerName: 'Athlete', field: 'athlete' }, { headerName: 'Sport', field: 'sport' }, { headerName: 'Age', field: 'age' } ], // other grid options here... }
二、模板定义,好比 Ignite UIthis
<igx-grid igxPreventDocumentScroll #grid1 [data]="data | async" [height]="'500px'" width="100%" [autoGenerate]='false' [allowFiltering]="true"> <igx-column [field]="'Category'" [width]="'120px'"></igx-column> <igx-column [field]="'Type'" [width]="'150px'" [filterable]='false'></igx-column> <igx-column [field]="'Open Price'" [width]="'120px'" dataType="number" [formatter]="formatCurrency"> </igx-column> <igx-column [field]="'Price'" [width]="'120px'" dataType="number" [formatter]="formatCurrency"></igx-column> </igx-grid>
权衡各类利弊,Extensions Data Grid 选择了第一种定义方法,接口定义以下:
export interface MtxGridColumn { field: string; header?: string; hide?: boolean; disabled?: boolean; pinned?: 'left' | 'right'; left?: string; right?: string; width?: string; resizable?: boolean; sortable?: boolean | string; type?: 'tag' | 'button' | 'link' | 'image' | 'number' | 'currency' | 'percent' | 'boolean'; tag?: MtxGridColumnTag; buttons?: MtxGridColumnButton[]; formatter?: (rowData: any, colDef?: any) => void; cellTemplate?: TemplateRef<any> | null; showExpand?: boolean; description?: string; i18n?: string; summary?: ((colData: any, colDef?: any) => void) | string; }
模板是 angular 组件极其灵活的一个功能。大部分优秀的第三方组件都具备自定义模板的能力,而在 Data Grid 中,模板更是一个不可或缺的功能。Extensions Data Grid 的模板功能已经比较完善,单元格模板除了基本的方法外,还增长了更为简单易用的方法。
<mtx-grid [data]="list" [columns]="columns"> </mtx-grid> <ng-template #statusTpl let-row let-index="index" let-col="colDef"> <mat-slide-toggle [checked]="row.status">Slide me!</mat-slide-toggle> </ng-template>
export class AppComponent implements OnInit { @ViewChild('statusTpl', { static: true }) statusTpl: TemplateRef<any>; columns: MtxGridColumn[] = []; list = EXAMPLE_DATA; ngOnInit() { this.columns = [ { header: 'Name', field: 'name' }, { header: 'Weight', field: 'weight' }, { header: 'Gender', field: 'gender' }, { header: 'Mobile', field: 'mobile' }, { header: 'City', field: 'city' }, { header: 'Status', field: 'status', cellTemplate: this.statusTpl }, ]; } }
官网示例: Custom cell template
引用模板实例是一种很常见的思路,可是弊端就是必须将列定义写在 ngOnInit 中,并且要先引用所用的自定义模板实例。这种写法很不灵活。
<mtx-grid [data]="list" [columns]="columns" [cellTemplate]="{ city: cityTpl }"> </mtx-grid> <ng-template #cityTpl let-row let-index="index" let-col="colDef"> <button mat-raised-button color="primary">{{row.city}}</button> </ng-template>
官网示例: Custom cell template 2
这种方法直接在组件参数中定义了模板实例 [cellTemplate]="{ city: cityTpl }"
,其中 city
是列定义中的 field
,除此以外不须要再写其它任何代码,很是简单!
除了单元格模板以外,还有 headerTemplate、summaryTemplate、toolbarTemplate 等,能够知足大部分的个性化需求,详情见官网示例。
官网示例: Row selectable
表格的行选取是一个很常见的需求,用途普遍。默认开启单元格选取,能够设置 [cellSelectable]="false"
以关闭单元格选取。
经过 [rowSelectable]="true"
能够开启行选取。
<mtx-grid [data]="list" [columns]="columns" [rowSelectable]="rowSelectable" (rowSelectionChange)="log($event)" (cellSelectionChange)="log($event)"> </mtx-grid>
经过 [multiSelectable]="true"
能够设置多选行。这里有一个细节,按住 ctrl 并单击才能够多选,或者直接点击 checkbox 也能够。若是须要隐藏 checkbox,只须要设置 [hideRowSelectionCheckbox]="true"
。
若是初始化表格时但愿默认选中某些行,则只须要定义 [rowSelected]=[...]
。
设置不可选取行的方式有两种,一种是设置 checkbox 为 disabled,另外一种是隐藏 checkbox。配置很是简单,只须要经过 rowSelectionFormatter
过滤数据便可。
<mtx-grid [data]="list" [columns]="columns" [rowSelectable]="true" [rowSelectionFormatter]="rowSelectionFormatter"> </mtx-grid>
export class AppComponent { columns: MtxGridColumn[] = [ { header: 'Name', field: 'name' }, { header: 'Weight', field: 'weight' }, { header: 'Gender', field: 'gender' }, { header: 'Mobile', field: 'mobile' }, { header: 'City', field: 'city' }, ]; list = EXAMPLE_DATA; rowSelectionFormatter: MtxGridRowSelectionFormatter = { disabled: (data) => data.name === 'Boron', hideCheckbox: (data) => data.name === 'Helium', }; }
官网示例: Expandable row
行展开的实现借助了 Angular Material 表格的 multiTemplateDataRows
参数,实现细节不少。Data Grid 的代码以下:
设置 expandable
和 expansionTemplate
<mtx-grid [data]="list" [columns]="columns" [expandable]="true" [expansionTemplate]="expansionTpl"> </mtx-grid> <ng-template #expansionTpl let-row> {{row.name}} </ng-template>
在列定义中设置 showExpand
, 肯定在哪一个列显示展开符号。
export class AppComponent { columns: MtxGridColumn[] = [ { header: 'Name', field: 'name', showExpand: true }, { header: 'Weight', field: 'weight' }, { header: 'Gender', field: 'gender' }, { header: 'Mobile', field: 'mobile' }, { header: 'City', field: 'city' }, ]; list = EXAMPLE_DATA; }
官网示例: Column hiding & moving
列的显示隐藏以及排序是很是常见的需求,这类需求曾被产品经理折磨了无数次。目前的列操做 UI 只有菜单方式,以后还会添加侧边栏的 UI,暂时不支持列的横向拖拽。
列的操做彻底能够移到组件以外,经过设置 columns 实现,并不必定非要用 Data Grid 集成好的功能。
因篇幅有限,不少 Extensions Data Grid 的功能没有详细介绍。从我遇到的需求来看,目前的 Data Grid 已经能够覆盖九成的需求了,还有不少高级功能正在开发当中,欢迎你们提出建设性意见。若是你们在使用组件的过程当中遇到问题,能够在 GitHub 中提交 issues 或者进讨论群提问。