原作者:Kris Zyp
原文链接:http://dojotoolkit.org/documentation/tutorials/1.6/store_driven_grid/
译者:zhuxw([email protected])
鉴于DataGrid对于表格数据的有效呈现,它早已成为许多应用的核心组件之一。在本教程中,我们将着眼于如何为grid连上store(Dojo的客户端数据集——译者注),以进行快捷高效的数据读取和更新。
难度:初等
Dojo版本:1.6
首先,我们将创建一个store。在本例中将创建一个JsonRest store,它将通过JSON REST HTTP成为连接grid和我们的服务器的纽带。创建代码如下:
dojo.require("dojo.store.JsonRest"); myStore = new dojo.store.JsonRest({target:"MyData/"});
以上代码表明这个store将向给定的URL("MyData/")发送请求,以获取或修改数据。
注意:其他类型的store也能使用,例如dojo/store/Memory(原文有误,并不存在dojo/data/Memory。 ——译者注),也能够驱动DataGrid。然而本教程只采用 JsonRest store。
现在我们可以创建DataGrid了。在1.6版中DataGrid仍然基于dojo.data API,因此我们将使用接口适配器dojo.data.ObjectStore来连接DataGrid和我们刚刚创建的store。DataGrid采用标准的Dojo小部件的构造方式,因此我们可以用我们的store作为参数来实例化一个DataGrid(同时请确保已经导入了正确的CSS文件(例如使用claro主题的话,可导入dojox/grid/resources/claroGrid.css。——译者注))
dojo.require("dojox.grid.DataGrid"); dojo.require("dojo.data.ObjectStore"); dojo.ready(function(){ grid = new dojox.grid.DataGrid({ store: dataStore = dojo.data.ObjectStore({objectStore: myStore}), structure: [ {name:"State Name", field:"name", width: "200px"}, {name:"Abbreviation", field:"abbreviation", width: "200px"} ] }, "target-node-id"); // make sure you have a target HTML element with this id grid.startup(); });
现在我们已经创建好了grid,当它启动完成后(即调用grid.startup()后——译者注),将调用store的query()方法,从而触发一个请求来获取数据。服务器需要返回一个包含数据的JSON数组作为响应,这样,grid就会将这些数据渲染出来。这个JSON数组形式的响应看上去就像这样:
[ {"id":0,"name":"Alabama","abbreviation":"AL","capital":"Montgomery"}, {"id":1,"name":"Alaska","abbreviation":"AK","capital":"Juneau"} ]
好了,现在我们已经有了一个可以正常工作的grid,它能从我们的服务器获取数据。接下来我们来看一下如何增强我们这个组件。
通过响应滚动鼠标滚轮事件来实现即时分页是Dojo DataGrid的强大功能之一。它为浏览大数据集提供了无缝、直观的用户体验——无需点击任何分页控件,只需简单地滚动滚轮即可看到更多数据。这种即时分页是通过向store不断发送一种特殊的请求实现的,这种请求限制了每次返回的数据行数。grid将给store的query()方法传一个请求对象作为其第二个参数,这个对象中有两个属性:start和count。JsonRest store通过HTTP头部属性Range将这两个参数发送到服务器端。这是一个对于可伸缩性非常重要的特性,因为这使得我们能够延迟加载在可视范围之外的行,而不是一下子加载所有数据。向服务器发出的第一个请求如下所示(你可以在浏览器的调试工具中方便地查看这些请求):
GET /MyData/ HTTP/1.1 Range: items=0-19 ...
http服务器可以通过Range头来确定需要向客户端发送多少行数据(例如,可以把这个Range头转化为MySQL服务器的LIMIT或OFFSET参数)。对于大规模的数据集,当你将grid向下滚动时,将触发后续的请求。这些后续请求也都具有Range参数,只不过偏移量(起始行号)不同罢了。grid并不直接向服务器发送请求,而是调用store的函数(这些都是自动完成的):
myStore.query("", {start: 0, count: 20}).then(...grid's callback...);
DataGrid还支持在点击列头时触发对数据排序的请求。出于性能考虑,grid将实际的排序工作交给了store去做,因为在数据库中进行排序的效率是最高的。当点击一列时,grid将向store发送一个带有sort参数的新请求,这个参数通过query()方法的第二个形参(是一个参数对象)传入。对于JsonRest store来说,这将告诉服务器,返回的数据需要按照某个属性排序(在本例中是“name”属性):
GET /MyData/?sort(+name) HTTP/1.1 Range: items=0-19 ...
grid内部通过下面的逻辑向store发出排序请求:
myStore.query("", {start: 0, count: 20, sort:[{attribute:"name"}]}). then(...grid's callback...);
grid这种与store的交互方式有一个很重要的特性,那就是这种请求数据的方式使得store的数据视图保持独立。这意味着如果我们在grid外直接向store请求数据,对于grid的显示是没有任何影响的。换句话说,grid对于store的请求只限于其自身,与其他请求是相互独立的。你无法直接对store排序,你只能获取一个排好序的数据视图,这个数据视图就是当你点击列头时grid显示的内容。
除了排序视图外,我们还可以创建过滤视图。这可以通过setQuery()方法做到。DataGrid将把这些参数传给store(和排序与分页一样,过滤数据也最好在数据库层面完成,这样的效率最高)。例如,过滤出所有缩写为“NY”的行,只需要这样写:
grid.setQuery({abbreviation: "NY"});
这句话将触发一个如下请求:
GET /MyData/?abbreviation=NY HTTP/1.1 Range: items=0-19 ...
这个请求也将被转化为合适的数据库查询。
在Grid内部,传给setQuery方法的这个请求是作为store.query()方法的第一个参数。如果使用的是JsonRest store,这个请求最终会转化为字符串,接在URL后面以http GET方法的形式发送到服务器端。
DataGrid支持双击后(或单击后)直接编辑单元格,可以提供很好的用户体验。DataGrid通过统一的数据接口将改动写回store。一旦编辑了一个单元格,改变后的数据通过Dojo数据适配器的setValue方法写回,在未保存之前暂时留在适配器中,直到调用了save()方法:
dataStore.save();
调用save()方法后,所有未保存的改动都会通过put()方法保存到store中。
注意:DataGrid经常需要通过ID获取对象。为了避免向服务器发送多余的请求,还可以为store加上一层Cache缓存,从而在本地快速存取缓存的对象:
dojo.require("dojo.store.JsonRest"); dojo.require("dojo.store.Memory"); dojo.require("dojo.store.Cache"); myStore = dojo.store.Cache( dojo.store.JsonRest({target:"MyData/"}), dojo.store.Memory());
DataGrid是一个功能强大、丰富的表格控件,提供伸缩式的表格数据渲染,还包括排序、过滤、列移动、选择、编辑、键盘导航等等。DataGrid与store的紧密联系使得在Grid中对数据处理进行配置非常容易。