1. 中国对外贸易中心(集团) 笔试 广州
Gridx 脱离了 DataGrid 的框架,具有高度模块化的设计,使其能适应各种使用场景的需要。大量针对 DataGrid/EnhancedGrid
的问题而做出的设计上的改进使 Gridx 具有更高的稳定性和更好的性能。同时,API 的设计更直观,且难以被误用。本文从如何创建和使用 Gridx 入手介绍了
Gridx 的基本特点和基本用法,目的是让您对 Gridx 有一个基本的了解。
[size=0.76em]准备工作
[size=0.76em]Gridx 是基于 Dojo 的开源项目,在 GitHub
或者其官网都可以下载到源码包。下载解压后将 gridx 文件夹置于与 dojo、dijit 和 dojox 等文件夹同级的目录即可。目前 Gridx 支持
Dojo1.7+。
[size=0.76em]gridx/tests
文件夹中有大量的示例页面,可以从修改这些示例页面开始学习使用 Gridx。
[size=0.76em]回页首
[size=0.76em]创建 Gridx
[size=0.76em]Gridx 继承了
dijit._WidgetBase,因此其创建方式和其他 widget
类似,只是有一些必须指定的参数需要特别说明。
[size=0.76em]选用合适的 store 和
cache
[size=0.76em]Gridx 与 DataGrid 一样,都以 Dojo 的
store 作为数据源。不过,Gridx 需要用户指出所用的 store 是异步的还是同步的。异步 store
通常由服务器端提供数据,向它请求数据时往往需要异步地接收返回数据;而同步 store 的所有数据一般都在客户端,因此所有的请求都能同步完成。异步 store
往往会带来更为复杂的逻辑,因此 Gridx 针对这两种 store 分别进行了优化。但由于无法从 store
本身得知它是否异步,同时为了减小代码量,用户需要将这个信息告知 Gridx。告知的方法是设置 cacheClass
参数:
清单 1. 创建 Gridx 并配置 cacheClass 参数
require([ "gridx/Grid",
"gridx/core/model/cache/Sync", ...... "dojo/domReady!" ],
function(Gridx, Cache, ......){ ...... var grid = new Gridx({
cacheClass: Cache store: store, ...... });
grid.placeAt('gridContainerNode'); grid.startup(); });
[size=0.76em]目前 Gridx 有两种 cache
实现:gridx/core/model/cache/Sync 和 gridx/core/model/cache/Async,前者用于同步
store,后者用于异步 store。Async 的实现逻辑比 Sync
要复杂得多,这是因为它需要考虑数据的延迟加载。这样,如果用户的应用只需要客户端数据,就完全不必用到关于延迟加载的代码,从而减小了最终下载到浏览器的代码量。
[size=0.76em]cacheClass 既可以直接接受 cache
实现的构造函数(如上例),也可以接受 MID,例如:
[size=0.76em]清单 2. 用 MID 设置 cacheClass
参数
var grid = new Gridx({ cacheClass:
"gridx/core/model/cache/Async" ...... });
[size=0.76em]这种写法更适合以 HTML 声明的方式创建 Gridx
的场合,因为它不需要引入额外的变量。
[size=0.76em]目前 Gridx 能够直接支持 dojo(x)/data/* 的老
store 以及 dojo/store/* 的新 store,而不需要任何适配转换。常用的同步 store 有
dojo/data/ItemFileWriteStore 以及 dojo/store/Memory。常用的异步 store 有
dojox/data/JsonRestStore、dojox/data/QueryReadStore 以及
dojo/store/JsonRest。
[size=0.76em]需要特别注意的是,Gridx 要求 store
中的数据行必须具有唯一标识符(ID)。对于老 store 而言,也就是必须要实现 dojo/data/api/Identity
一维数组结构的列声明
var grid = new Gridx({ cacheClass:
Cache store: store, structure: [ {id: 'column1', ......},
{id: 'column2', ......}, {id: 'column3', ......}, ......
] });
[size=0.76em]下面各小节详细介绍列声明中各个属性的含义。
[size=0.76em]id、name、field
[size=0.76em]对于 Gridx
来说,每一列都有一个唯一标识符(ID)。用户最好能指定一些有意义的 ID,从而方便以后的使用。如果用户没有指定,那么 Gridx 会分别赋予"1", "2",
"3", ....... 等字符串类型的自然数作为列的默认 ID。
[size=0.76em]与 DataGrid 类似,name
属性是指表头上显示出来的列名。name 属性可以是任意字符串,甚至可以包含 HTML 标签,从而做出各种定制效果。例如:{id: 'column1',
name: '<b>Company
<i>Name</i></b>'}。
[size=0.76em]field 属性也是从 DataGrid 沿袭下来的,指该列在
store 中的对应域。该列中的单元格会从这个 field 域中取得数据。
[size=0.76em]图 1. name 属性作为普通字符串、未指定、以及带 HTML/CSS
的各种情况
[size=0.76em]formatter
函数
[size=0.76em]Gridx 的 formatter 函数与 DataGrid
中的同名函数不同,其目的在于为 Gridx 提供数据,而不是对数据做显示上的修饰。如果某一列没有 field 参数,就可以通过 formatter
函数来提供数据,例如:
[size=0.76em]清单 4. 使用 formatter
函数组合多个域的数据
{id: 'column1', formatter:
function(rawData){ return rawData.field1 + rawData.field2; });
[size=0.76em]这样,这一列就能显示两个数据域的和。
[size=0.76em]图 2. formatter 函数综合多个数据域的内容产生了 Summary
列中的数据
[size=0.76em]formatter 函数所传入的 rawData 参数是以
store 的 field 名称作为 key
的关联数组(对象),包含当前行中的所有数据,形如:
[size=0.76em]清单 5. rawData 格式
rawData: { field1: data1, field2:
data2, ...... }
[size=0.76em]这种形式要比某些 store(主要是老
store)的数据项(item)更容易使用,也使接口与新 store 保持一致。
[size=0.76em]decorator
函数
[size=0.76em]Gridx
对数据的产生和数据的修饰做了严格的区分。formatter 是用于产生数据,decorator
函数则用于修饰数据。例如:
[size=0.76em]清单 6. 用 decorator 函数为单元格添加
HTML/CSS
{id: 'column1', field: 'field1',
decorator: function(cellData, rowId, rowIndex){ return "<a
href='www.google.com?q=" + cellData + "'><b>" + cellData +
"</b></a>"; } }
[size=0.76em]这样就能在单元格中显示出链接。
[size=0.76em]图 3. 使用 decorator
对数据做修饰
[size=0.76em]decorator 函数只能返回字符串,不像 DataGrid 的
formatter 函数还可以返回 widget 实例。关于如何在单元格中显示 widget
的问题将在其他文章中详细介绍。
[size=0.76em]style 和
class
[size=0.76em]通过在 decorator 函数中加入 HTML 标签和
style 属性可以对单元格中的内容做各种修饰,但无法改变单元格本身的样式。要做到这一点,需要 style 或
class:
[size=0.76em]清单 7. 字符串形式的 style 和 class
参数
{id: 'column1', field: 'field1', style:
'text-align: center;', 'class': 'mySpecialColumn' }
[size=0.76em]style 和 class 都会直接加入到 <TD>
标签的 style 属性和 class 属性。
[size=0.76em]style 和 class
还可以写成一个返回字符串的函数,这样单元格的样式就能随数据而变化:
[size=0.76em]清单 8. 函数形式的 style 和 class
参数
{id: 'column1', field: 'field1', style:
function(cell){ return cell.data() % 2 ? 'color: red;' : 'color:
blue;'; }, 'class': function(cell){ return cell.data() %2 ?
'oddClass' : 'evenClass'; } }
[size=0.76em]这里 style 和 class 函数所传入的 cell
参数代表了当前所处理的单元格,可以通过各种方便的方法获取有关该单元格的一切信息。
[size=0.76em]图 4. 使用 style
函数为每一个单元格设置独特背景色的例子
[size=0.76em]配置功能模块
[size=0.76em]有了 store、cacheClass 和 structure
后,Gridx 就能运行了。不过这样的 Gridx 除了显示数据之外,几乎没有任何界面功能。Gridx
几乎所有的功能都是由可选模块(mole)实现的,需要在创建时声明使用了那些模块。这提供了巨大的灵活性来满足各种不同的需求。
[size=0.76em]声明模块的是 moles
属性:
[size=0.76em]清单
9. 通过 moles 参数配置功能模块
require([ "gridx/Grid",
"gridx/core/model/cache/Sync", "gridx/moles/VirtualVScroller",
"gridx/moles/ColumnResizer", "gridx/moles/Focus",
"gridx/moles/SingleSort", ...... dojo/domReady!" ], function(Gridx,
Cache, VirtualVScroller, ColumnResizer, Focus, SingleSort, ......){ ......
var grid = new Gridx({ cacheClass: Cache store: store,
structure: structure, vScrollerLazy: true,// 模块参数可作为 Gridx 参数传递
moles: [ VirtualVScroller, // 用法 1:直接列举模块构造函数
"gridx/moles/ColumnResizer", // 用法 2:模块 MID {
// 用法 3:带有 moleClass 的对象 moleClass: SingleSort,
initialOrder: { colId: 'column1', descending: true } },
{ // 用法 4: moleClass 也接受 MID moleClass:
"gridx/moles/Focus" } ] }); ...... });
[size=0.76em]从上面的例子可见,要使用一个模块先要引入该模块的文件,然后直接列举在
moles 数组中即可。moles 数组中的模块既可以是模块构造函数本身,也可以是模块的 MID,还可以是一个含有 moleClass
属性的对象。模块本身也可能有参数,这些参数既可以与 moleClass 一起放在一个对象里(如 initialOrder),也可以直接作为 Gridx
的参数,只不过需要加上所属模块的名称作为前缀(如 vScrollerLazy,这里 vScroller 是模块名称,lazy
是属性名,加上前缀后首字母大写)。模块参数直接作为 Gridx 参数可以使代码更为简洁,因此是推荐的配置方法。
[size=0.76em]上面的例子中加入了 4 个模块:VirtualVScroller
实现了延迟渲染的功能,每次只渲染出需要显示的行,从而可以很快地完成拥有大量数据的 Grid 的创建;ColumnResizer
实现了鼠标拖动改变列宽的功能;SingleSort 是一个单列排序的简单实现;Focus 模块则是对键盘的支持,这是一个被许多其他模块引用的模块,对于 A11y
非常重要。
[size=0.76em]熟悉 DataGrid 的用户会发现这些功能在 DataGrid
中都是默认自带的。虽然这些功能很常用,但用户在不需要它们的时候却难以屏蔽;即使能够屏蔽它们的功能,大量的有关这些功能的代码也依旧存在,而这不失为一种浪费。
[size=0.76em]图 5. 启用了排序、分页、改变列宽、行选择、行首勾选框等多个模块的
Gridx
[size=0.76em]Gridx 的模块化是其最大的特点之一。其实 Gridx
的所有用户界面(包括表头、数据行、纵向滚动条、横向滚动条等)都是模块,只不过这些模块是默认加载的核心模块而已。所谓创建 Gridx
其实就是在一个很小的逻辑内核(称为 Core)的基础上依次创建这些模块。模块之间秉承低耦合的原则,只以 API
和功能相联系而不涉及具体实现,因此几乎所有的模块都是可替换的。同时模块本身是高内聚的,使得维护和调试也更为方便。
[size=0.76em]其他配置参数
[size=0.76em]Gridx 本身还有少数几个参数:如 autoHeight 和
autoWidth,可以由行高和列宽来决定 Gridx 的高度和大小;使用 cache/Async 时的 cacheSize
参数可以配置保存在客户端的最大行数,而 pageSize 可是每次向 store 请求数据时的推荐请求行数。这些参数只有在特殊需求下才有必要使用,具体用法可关注
Gridx 文档。
[size=0.76em]创建 Gridx 时还有一个基本要求就是要指定 Gridx
的大小。Gridx 与 DataGrid 不同,没有默认高度(DataGrid 有 6em 的默认高度),因此必须通过 CSS 为 Gridx
指定高度(除非使用 autoHeight)。同样,也没有默认宽度。
[size=0.76em]目前 Gridx 只支持 Claro 主题,通过
gridx/resources/claro/Gridx.css 可以引入所有与 Gridx 相关的样式。若要支持 RTL,还需要引入
gridx/resources/claro/Gridx_rtl.css。
[size=0.76em]图 6. RTL 状态下采用了 autoWidth 的
Gridx
[size=0.76em]回页首
[size=0.76em]使用 Gridx
API
[size=0.76em]Gridx 本身的 API 很少,主要的 API
来源是其数据模型(grid.model)和各个模块。
[size=0.76em]数据模型 API
[size=0.76em]Gridx 的数据模型(grid.model)是其 MVC 模式的
M 部分,是整个 Grid 的数据层和逻辑层,没有任何用户界面(甚至可以单独使用)。grid.model 的 API 就是为了与 Gridx
的数据进行便捷的交互。主要 API 有:
[size=0.76em]清单 10. grid.model 的常用
API
grid.model.byIndex(rowIndex); grid.model.byId(rowId); grid.model.indexToId(rowIndex); grid.model.idToIndex(rowId); grid.model.size(); grid.model.when(request,
callback);
[size=0.76em]可见除了最后一个 when 函数,都是取数据的 API。这个
when 函数是数据模型中唯一的异步函数,它可以接受一个回调函数作为参数,也会返回一个 Deferred 对象。其语义是:当所请求 request
的数据行都已加载到客户端,且所有改变数据的操作都完成时,调用回调函数
callback。因此典型的用法是:
[size=0.76em]清单 11. grid.model.when
的用法
grid.model.when([1, 3, 5, 7, 9],
function(){ // 获取第 5 行的 ID var rowId = grid.model.indexToId(5); // 获取第
1 行的数据 var rowData = grid.model.byIndex(1).data; // 获取第 9 行的 item var
storeItem = grid.model.byIndex(9).item; });
[size=0.76em]这里的 [1, 3, 5, 7, 9] 是用 index
的方式来请求行。Gridx 也支持通过范围的方式来请求行:
grid.model.when({start: 0, count: 20}, ....);
[size=0.76em]或是用 ID
来请求行:
grid.model.when({id: ['row1', 'row2']}, ....);
[size=0.76em]更多用法请参见文档。
[size=0.76em]grid.model 还有一些 API
可以对数据行的顺序进行改变或者过滤,例如:
[size=0.76em]清单 12. 改变数据模型的 API
grid.model.sort(); grid.model.query(); grid.model.filter(); grid.model.move();
[size=0.76em]这些功能其实是由 model
的扩展(modelExtension)实现的。如果今后出现了其他类型的数据操作需求,就可以以这种扩展的形式进行补充。
[size=0.76em]注意到 Gridx
的数据模型没有提供插入、删除、修改数据的方法,这是因为这些操作都可以直接通过 store 的 API 来完成,Gridx
并不需要提供重复的接口。
[size=0.76em]模块 API
[size=0.76em]模块 API 是 Gridx 的另一大 API 来源。Gridx
的几乎所有模块都可以通过 Gridx 实例直接访问到。例如:
[size=0.76em]清单 13. 访问模块 API
grid.sort.clear(); // 调用 sort 模块的
clear 方法。 grid.columnResizer.setWidth(); // 调用 columnResizer 模块的
setWidth 方法。 grid.select.row.getSelectedIds(); // 行选择模块的 getSelectedIds
方法 grid.select.column.selectById(); // 列选择模块的 selectById 方法 //
甚至核心模块也不例外: grid.header.hidden =
true; grid.body.refresh(); grid.vScroller.scrollToRow();
[size=0.76em]由于每一个模块都有自己的名字空间,因此不容易引发命名冲突。有的模块(如行列选择等)甚至可以创造出更深层次的命名空间,从而使
API 的命名更精简。
[size=0.76em]Gridx 几乎所有主要的功能 API
都由模块提供,这其实简化了各个 API 的命名。例如 selectRow 模块和 selectColumn 模块都可以有 selectById
函数,命名精简的同时在使用的时候仍然具有清晰的语义。每个模块具体的 API 请参考 Gridx 文档。
[
2. 峰力的峰力听力集团发展大事记
2005年
2005年10月控股收购巴西最大的助听器批发和零售商CAS Protos Médicos公司。
2005年3月, Savia神雕系列超级数字仿生助听器在欧洲宇航局隆重推出,峰力听力大使、Savia助听器佩戴者、人类第一批第二个登月英雄巴兹奥尔德林(Buzz Aldrin)出席发布会。
Savia神雕超级仿生助听器荣获2005年度全球优秀医疗器械设计金奖
峰力陆续推出miniValeo、microSavia、和eXtra 等新产品。
2004年
在中国,峰力听力集团收购了峰力和优利康两大品牌代理商,建立了直属的营销子公司,以加强在中国这个重要市场的市场开拓力度。
峰力听力集团收购奥地利Viennatone Horgerate GmbH公司,归入峰力在奥地利的Hansaton公司旗下。
峰力听力集团推出了Valeo中高档全数字助听器系列新产品。
2003年
在中国增建了生产基地。
在日本设立了销售公司。
Perseo和MAXX上市。Perseo成为峰力公司旗舰产品,MAXX是峰力公司推出的第一个中档全数字助听器。
2002年
2002年20月1日,Valentin Chapero Rueda接替 Peter Pfluger出任峰力听力集团全球CEO。
2001年
2001年4月1日,峰力收购奥地利Hansaton Akustische Gerate GmbH公司。
与澳大利亚人工耳蜗公司科利耳关于FM的销售协议。
2000年
Peter Pfluger 接替Andreas Rihs出任CEO一职,Andreas Rihs继续担任董事局主席。
收购了当时排列世界第七位的加拿大优利康助听器公司,新的峰力听力集团跻身全球听力行业3强之列。
1999年
推出革命性全数字助听器Claro。
1997年
新的科技中心在Stafa建成。
峰力公司创始人之一、技术总监和生产总监Beda Diethelm脱离日常事物,由Peter Pfluger接任。
1996年
收购比利时Lapperre和挪威Stephensen公司。
1995年
带AudioZoom音频变焦技术的PiCS助听器在全球推广。
1994年
销售首次突破1亿瑞士法郎,1994年11月峰力公开上市约20%的股票。
1992年
PiCS助听器在全球的发布取得巨大成功。
在Murten创立峰力通讯公司,扩大FM无线通讯业务。
1989年
在美国设立销售公司。
1987年
公司搬迁到Stafa新厂房(“峰力之家”)
1985年
成立Phonak Holding Ltd公司,作为峰力集团控股公司。
1980年
Ernst Rihs过世,股份由他的两个儿子继承,与Beda Diethelm持股相当。
1978年
在德国和法国设立了第一批海外销售公司。
1965年
Ernst Rihs收购了该公司所有股份,Beda Diethelm和Andreas Rihs随后加入,几年以后Hans-Ueli Rihs加入,公司从此进入业务发展的新纪元。
1947年
由Franco-Belgian集团投资者投资成立AG für Elektroakustik公司,总部位于苏黎世。