在Angular 2中构建高效的数据网格,首先需要掌握数据网格的基础知识。FlexGrid最初于1996年使用C++编写,用于Visual Basic(甚至作为Visual Studio的一部分提供)。自那时起,它已经经历了多次演变和改进,最新的版本是JavaScript。FlexGrid的名称来源于“Flex哲学”:控件应该只包含所需的关键功能集,并通过可扩展性模型提供其他所有功能。排序、分组和编辑等特性是内置的,而其他附加功能则作为FlexGrid的可选扩展提供。这使得控件保持小巧且快速,并且使和客户都能够构建自定义功能。
性能是FlexGrid的另一个关键特性。FlexGrid不断与其他网格进行基准测试,以确保速度。Flex哲学使能够保持非常小的文件大小(约25K Gzipped),并且对其他库没有依赖。通过虚拟渲染实现的最显著的性能改进。FlexGrid虚拟化了其所有DOM,并且只渲染填充视口所需的单元格(以及一些额外的缓冲区,以实现平滑滚动)。当网格滚动时,单元格(DOM元素)会被回收。虚拟渲染意味着网格可以在不到一秒钟的时间内绑定到数百万条记录。
最后,最重要的特性之一是熟悉度。FlexGrid几乎所有的交互行为都基于Excel,这可能是任何最终用户使用的最常用的网格/表格。当滚动、点击以及特别是使用键盘命令(包括剪贴板功能)时,人们期望某些行为。没有发明自己的行为,而是模仿了Excel的,最终用户立即感到舒适地使用网格。令人惊讶的是,许多其他网格要么发明了自己的行为,要么不完全支持键盘操作或滚动。例如,如果在网格中选择一行并按住向下箭头键,许多网格的运行方式并不像预期的那样。
现在,让来谈谈FlexGrid在Angular中的一些特定优势。FlexGrid在Angular中的最大优势是其标记:Angular组件使能够声明UI控件。声明性标记非常适合遵循MVVM设计模式,可以在视图(标记)中完全配置组件。
如果组件支持它,那么FlexGrid支持使用Angular标记声明其整个API。可以设置属性、附加事件、完全在标记中配置子组件(如列)。以下是一个如何在Angular 2标记中配置FlexGrid的示例:
<wj-flex-grid [itemsSource]="data">
<wj-flex-grid-column [header]="'Country'" [binding]="'country'" [width]="'*'"></wj-flex-grid-column>
<wj-flex-grid-column [header]="'Date'" [binding]="'date'"></wj-flex-grid-column>
<wj-flex-grid-column [header]="'Revenue'" [binding]="'amount'" [format]="'n0'"></wj-flex-grid-column>
<wj-flex-grid-column [header]="'Active'" [binding]="'active'"></wj-flex-grid-column>
</wj-flex-grid>
通过使用完全支持声明性标记的组件,可以获得真正的MVVM支持,并可以像在其他开发平台(ASP.NET、Java、Silverlight、Flex)中一样构建应用程序。
除了在标记中声明FlexGrid的任何成员外,还提供了单元格模板。单元格模板是声明不同类型单元格的可重用模板的方式。单元格模板支持任何有效的Angular标记,包括绑定表达式、HTML和其他组件。不同类型的单元格模板包括:标题单元格、编辑模式下的单元格、普通模式下的单元格等。
通过提供单元格模板,FlexGrid为提供了一种表达性的方式来创建组件。不仅可以在标记中利用FlexGrid的API,还可以在每个单元格中利用Angular的所有语法。
<wj-flex-grid [itemsSource]="data1" [allowSorting]="false" [deferResizing]="true">
<template wjFlexGridCellTemplate [cellType]="'TopLeft'" *ngIf="customTopLeft">?</template>
<template wjFlexGridCellTemplate [cellType]="'RowHeader'" *ngIf="customRowHeader" #cell="cell">{{cell.row.index}}</template>
<wj-flex-grid-column header="Country" binding="country" width="*">
<template wjFlexGridCellTemplate [cellType]="'Cell'" *ngIf="customCell" #item="item">
<img src="resources/{{item.country}}.png" /> {{item.country}}
</template>
</wj-flex-grid-column>
<wj-flex-grid-column header="Downloads" binding="downloads" [width]="170" [aggregate]="'Sum'">
<template wjFlexGridCellTemplate [cellType]="'ColumnHeader'" *ngIf="customColumnHeader">
<input type="checkbox" [(ngModel)]="uiCtx.highlightDownloads" /> Downloads
</template>
<template wjFlexGridCellTemplate [cellType]="'Cell'" *ngIf="customCell" #item="item">
<span [ngStyle]="{color: uiCtx.highlightDownloads? (item.downloads>10000 ?'green':'red'):''}" style="font-weight:700">{{item.downloads}}</span>
</template>
</wj-flex-grid-column>
</wj-flex-grid>
通过使用Angular的绑定表达式,可以创建自动响应数据变化的UI,从而避免了编写过多的事件处理程序和DOM操作。
最后但并非最不重要的一点是,FlexGrid和Wijmo的所有内容都是用TypeScript编写的。在Microsoft平台上有着悠久的历史,所以当TypeScript出现时,感到非常自在。TypeScript为提供了与C#相当的开发体验:得到了类、继承、强类型、类型检查、构建时的错误检查等等。它已经成为创建企业级JavaScript控件的催化剂,就像在其他平台上所做的那样,在API或语法中没有做出任何妥协。
也许最重要的是,TypeScript使能够创建“真正的控件”(作为类),而不是像几乎所有其他组件那样的小部件(作为函数)。FlexGrid是基础控件类的派生类。虽然小部件迫使使用一个尴尬的函数来设置一个属性并传入一个值,但FlexGrid具有具有getter和setter的属性,以便可以直接分配它们。Wijmo还有一个事件模型,用于轻松添加处理程序。
选择在TypeScript中工作(现在许多Angular 2用户都会这样做)的最终用户也将从控件中受益:他们在支持它的IDE中获得智能感知(或自动完成)代码、警告以及如果他们尝试为属性分配不正确的类型时的有用错误消息。
TypeScript最强大的特性是客户可以从控件中继承并扩展。这与Flex哲学一致,简化了控件定制并减少了错误。
最后,与Angular 2的现状保持一致。看到Google团队证实了几年前做出的决定真是太神奇了——采用了微软语言!控件类已经用TypeScript编写,所以它们非常适合Angular 2。只需要扩展它们并添加元数据装饰器,将它们公开为Angular 2组件。