提高 Dojo Grid 的数据处理性能

0

作者:孙妍,软件工程师,IBM

简介:Dojo 从 1.0 开始引入了一个功能强大又健壮的控件—— Grid。程序员可以使用此控件在开发 Gui 程序时制作出漂亮的电子表格。Gui 程序最注重的一个方面就是用户体验,但是在往 Grid 中添加大量数据的时候,程序的响应通常非常慢。本文通过一些方法来提高 Dojo Grid 的增加数据时的性能,增强用户体验。

Dojo Grid 在结构上有点类似于大家熟悉的 MVC 模式。MVC 模式是“Model-View-Controller”的缩写,也就是“模型 - 视图 - 控制器”。


图 1.MVC 结构

一个最简单的 Grid 在结构上主要有以下几方面构成:

  • 模型 (Model)

每个 Grid 都会包含数据,所以每个 Grid 开头都会去定义 Model。如清单 1 中的定义,Model 包含了 dojotype(dojo 模型类),jsid(专用 id),structure(结构),Store(数据库)等。 其中比较重要的部分是 Store,它放置了 Grid 中存储的数据。


清单 1. Grid 的定义

				
<div id="grid1" dojotype="dojox.grid.DataGrid" jsid="modelGrid" rowselector="0px"
canSort="false" structure="modelGridLayout" Store="modelStore"></div>

  • 视图 (View) 和结构 (Structure)

View 用来定义每个数据列,一个 View 是多个数据列的组合。通过定义 View,使 Grid 按照要求来显示数据。 Structure 是 View 的集合,也就是说可以将多个 View 组合成一个 Structure。Structure 会被 Grid 用到,而 View 不会被 Grid 直接用到, 而是被包装成一个 Structure 来使用。清单 2 中是一个 Grid Layout 的范例,它定义了 Grid 的结构。cells 部分定义了 Grid 列定义的信息。 每一列需要定义 name、id、field,以及列的 html 形式如长宽高之类的。之后对 Grid 列的操作主要是针对 field 域。


清单 2. Grid Layout 的定义

				

ModelGridLayout = [{
cells: [
{ name:'<div style="width:20px;height:20px;"><input type="checkbox"
onclick="DeviceGridRevertSelectAll(this)" id="checkcollection"></div>',
field: 'Sel',editable: true,width: '20px',cellStyles: 'text-decoration: none;
cursor:default; text-align: center;position: relative; left: -10px',headerStyles:
'text-align: center;',type: dojox.grid.cells.Bool },

{ name: 'Model',field: 'Model',width: '170px',cellStyles:'font-size:9pt;
cursor: default;text-align: left;',cellClasses: 'defaultColumn',headerStyles:
'text-align: center;'},

{ name: 'Device',field: 'Device',width: '150px',cellStyles: 'font-size: 9pt;
font-style:normal,text-decoration: none; cursor:default;text-align: left;',
cellClasses: 'defaultColumn',headerStyles: 'text-align: center;'},
]
}];

  • Grid 控件 (Widget)

这里的 Grid 控件类似于 MVC 中的控制器(Control)。通过 Grid 各种预先定义的 API 对 Grid 的数据(Model), 视图(View)有效的组织起来,并进行操作。以达到有效控制 Grid 数据存取、更新、外观变化的目的。 从而显示出一个类似于电子表格的 Grid 列表。

Dojo Grid 的数据存储

在 Grid Model 的定义中,有一个叫 Store 的属性,它存储了与 Grid 相关联的数据,也就是 Grid 绑定到的数据源。 在示例中,数据源的名字叫 modelStore。modelStore 的定义如下:<div dojotype="dojo.data.ItemFileWriteStore" jsid="modelStore" url="data/modelItemList.json"></div>

Dojo 的核心提供了一个只读的数据体实现,ItemFileReadStore。这个数据体可以从 HTTP 端点读取 Json 结构体,或是读取内存中的 JavaScript 对象。 Dojo 允许为 ItemFileReadStore 指定某个属性来作为 identifier(唯一标识符)。Dojo 内核同时提供了 ItemFileWriteStore 存储作为 ItemFileReadStore 的一个扩展,它是建立在 dojo.data.api.Write 和 dojo.data.api.Notification API 对 ItemFileReadStore 的支持之上的。如果你的应用程序需要 写入数据到 ItemFileStore,则 ItemFileWriteStore 正是你所要的。

对于 Store 的操作,可以使用函数 newItem,deleteItem,setValue 来修改 Store 的内容,这些操作可以通过调用 revert 函数来取消, 或者调用 save 函数来提交修改。

在使用这些函数时,一定要注意的是,如果你为 ItemFileWriteStore 指定了某个属性来作为 identifier,必须要确保它的值是唯一的, 这对 newItem 和 deleteItem 函数特别重要,ItemFileWriteStore 使用这些 ID 来跟踪这些改变,这意味着即使你删除了一个 Item, 它的 identity 还是被保持为使用状态,因此,如果你调用 newItem() 并试图重用这个 identifier,你将得到一个异常。要想重用这个 identifier, 你需要通过调用 save() 来提交你的改变。Save 将应用所有当前的改变并清除挂起的状态,包括保留的 identifier。当你没有为 Store 指定 identifier 时, 则不会出现上述问题。原因是,Store 会为每个 Item 自动创建 identifier,并确保了它的值是唯一的。在这种自动创建 identifier 的情况下, identifier 是不会作为一个公有属性暴露出来的(它也不可能通过 getValue 得到它,仅 getIdentity 可以)。

Store 的数据存储在两个 json 数组中,名字分别为 _arrayOfAllItems 和 _arrayOfTopLevelItems。这两个数组的区别是在于前者记录了 Grid 创建以来 Store 中存在过的所有变量, 后者中只是存储 Store 当前的所有 Item。如果有变量被删除,则 _arrayOfAllItems 中该数组变量设为 null,而 _arrayOfTopLevelItems 中该数组变量会被彻底删除, 数组个数减一。这样的设定是为了在 Store.newItem 的时候,如果用户没有为 Store 指定 identifier,Store 可以自动地用 _arrayOfAllItems 的数量值为新 Item 创建 identifier。_arrayOfAllItems 的个数不会因为删除操作而减少,也就不必担心新 Item 的 identifier 就会发生重复。

程序清单 3 中描述了 Grid 自动创建 identifier 的过程,首先程序会尝试去获得之前定义的 Identifier 属性。如果属性是 Number 就把 _arrayOfAllItems.length 赋给 newIdentity。如果属性不是 Number, 就把 identifierAttribute 对应的 keywordArgs 赋给 newIdentity,如果 newIdentity 是空,就表示 identity 创建失败。

清单 3. Grid identifier 的创建

 var newIdentity = null; 
var identifierAttribute = this._getIdentifierAttribute();
if(identifierAttribute === Number){
newIdentity = this._arrayOfAllItems.length;
}
else{
newIdentity = keywordArgs[identifierAttribute];
if (typeof newIdentity === "undefined"){
throw new Error("newItem() was not passed an identity for the new Item");
}
}

图 2 则显示了当删除一个数据后,_arrayOfAllItems 和 _arrayOfTopLevelItems 的差别。_arrayOfAllItems 有个变量被置空,而 _arrayOfTopLevelItems 的个数减一了。


图 2. arrayOfAllItems 和 arrayOfTopLevelItems

Dojo Grid 了提供大量非常实用的 API,基于这些函数,程序员可以制作出漂亮的电子表格。但是在使用过程中, 它的一些性能问题就逐渐暴露出来。有个比较突出的问题就是在使用 newItem() 方法往 Grid 中添加大量数据的时候, 浏览器会因为 Grid 的操作而陷入忙碌,很长时间没有响应甚至白屏。而对于 UI 用户而言,快速稳定的页面响应是 他们所共同期望的。那么有没有什么办法能改善这一问题呢?

导致性能问题的原因


图 3.Grid 修改数据

Grid 修改数据的过程总是先修改 Grid 绑定到的 Store 中的数据,然后再根据需要,改变 Grid 的 View,完成 Grid 外表的更新。 在通常情况下,在 Grid 创建之时,如果定义了 Store,Grid 就会调用 this._setStore(this.Store); 来对自身的 Store 属性进行配置。 在 _setStore 这个函数里,Grid 对 Store 创建、删除、修改 Item 事件进行侦听。Grid 使用 dojo.connect() event model 来绑定一个自定义 的函数到 Store 上,当无论何时 Store 调用 onSet,onNew,and onDelete 时,都将调用这个函数。这个过程就如清单 4 中所描述的那样。 Grid 通过 this.connect 把 Store 的 onSet,and onDelete 事件和自身定义的 _onSet._onNew,_onDelete 链接起来了。


清单 4. Grid connect event

				

h.push(this.connect(this.Store,"onSet","_onSet"));
h.push(this.connect(this.Store,"onNew","_onNew"));
h.push(this.connect(this.Store,"onDelete","_onDelete"));

清单 5 展示了 Store 的 _onNew 事件处理函数。当程序使用 newItem 往 Store 里增加数据时,Store 在完成添加操作后会发出一个 dojo.data.api.Notification —— this.onNew(newItem,pInfo); Grid 监听到了这个 Notification 后就会调用之前定义过的 _onNew 处理函数,对自身进行操作。Grid 会分别更新自己的行数,增加新项目 (_addItem), 如有需要打印一些消息。


清单 5. Store _onNew()

				

_onNew: function(Item,parentInfo){
this.updateRowCount(this.rowCount+1); // 更新行数
this._addItem(Item,this.rowCount-1); // 增加新 Item
this.showMessage(); // 打印某些信息
}

在上面的三个步骤中,增加新的 Item 是最关键的。_addItem 的操作包括了获得新项目的 Identity,分配 Identity 空间,向 Identity 空间填充 Item,以及更新行视图(添加新的 dom 节点)。具体过程如清单 6 中所示。


清单 6. Grid _addItem()

				

_addItem: function(Item,index,noUpdate){
var idty = this._hasIdentity ? this.Store.getIdentity(Item) : dojo.toJson(this.query) +
":idx:" + index + ":sort:" + dojo.toJson(this.getSortProps()); // 获得 Identity
var o = { idty: idty,Item: Item }; // 分配获得空间
this._by_idty[idty] = this._by_idx[index] = o;// 向 Identity 空间填充 Item
if(!noUpdate){
this.updateRow(index);// 更新行视图
}
}

通过上面的分析,我们可以看到,如果使用 newItem 循环往 Store 中添加数据,那么 Store 在执行完一次 add 的操作后都会引发 Grid 去载入新加项目, 并更新自己的视图。经过实验发现,往 Store 中添加 Item 的速度是很快的,而 grid 的载入新加项和更新自身视图的操作是比较慢的。每次新加一个 数据,Grid 都会尝试把新加的数据都加载进来(创建所有的 dom node),虽然这保证了 Grid 获得 Store 当前的所有数据,但是这种操作加大了浏览 器的内存开销,更进一步使浏览器陷入忙碌,长时间没有响应。

Grid 性能问题的解决方法

要解决上述性能问题,需要解决三个方面的问题。

Step 1. 适时断开 Grid 和 Store 的连接

因为往 Store 中添加数据的速度很快,而 Grid 的载入新加项和更新视图速度较慢,所以在操作之初,就把 Grid 的 Store 设置为空(null), 断开 Grid 和 Store 的连接,deviceGrid._setStore(null);。这样即使 Store 因为 addItem 发生变化,也不会联动引起 Grid 的操作了。 当 Store 中添加完数据后再把 Grid 和 Store 链接上:deviceGrid._setStore(deviceStore); 最后把数据重新加载完成视图更新:deviceGrid.render()。 清单 7 中展示的就是这个过程,在添加数据之初 modelGrid 先断开 Store 的连接,再往 modelStore 中添加数据,结束后又把 modelStore 重新连接上 modelGrid.


清单 7. Grid 添加项目

				
function _addGridData(dataarray)
{
modelGrid._setStore(null); // 断开连接
/* 往 Grid 中添加数据 */
for(var i=0;i<datalength;i++){
var modelname = dataarray[i].split(',')[0];
var devicename = dataarray[i].split(',')[1];
modelStore.newItem({id:"modelItem"+i,StatusImage:'<img src="images/Normal_obj16.gif">',
Sel:true,Loop:1,Status:'<img src="images/statusStopped_obj16.gif">Not Started',
Model: modelname,Device: devicename});
}
modelGrid._setStore(modelStore);// 恢复连接
modelGrid.render();// 重新加在视图
}


Step2. 适应“lazy loading”数据加载机制

Dojo Grid 在获取 Item 时有一种机制叫做“lazy loading”。在 Grid 初始化时并不把 Store 里的所有数据都加载进来, 而是采用“on-demand”的方式进行数据加载。触发数据加载的事件是 Grid 滚动条的的拖拉动作。当滚动条被拖拉到某一个特定位置时, Grid 会计算出当前滚动条的位置,并把和当前位置相关的数据加载进来。数据加载是按照“页”为单位装载的。有两个比较重要的属性:
keepRows: 75 // Number of rows to keep in the rendering cache
rowsPerPage: 25 //Number of rows to render at a time,and the rows number in each page
在步骤 1 的最后,Grid 使用 render( ) 函数来取回表格、表头和视图,并把滚动条停留在 Grid 最顶端。因此,在 Grid 完成一次 render 后加载进来的数据只有 25 条。 其余的数据要在用户拖动滚动条后触发再按需加载进来。

这样的数据加载方式,固然是减小了内存开销,提高了页面加载速度。但如果此时使用 Grid 的 getItem:(idx) 函数,程序会因为 getItem 函数中的 var data = this._by_idx[idx]; 语句而报错。因为输入函数 idx 可能大于当前 Grid 加载进来的数据量,此时通过 idx 去 Grid 中索引 Item 就会导致数组越界报错。 也就是说在“lazy loading”的情况下,数据没有同时全部载入,这时如果企图通过 Grid.getItem(idx) 来操作 Store 中的所有数据的修改、删除是不安全的。

解决这一问题的方法是直接对 Store 中的数据进行获取、修改、删除。Store 中的 _arrayOfTopLevelItems 存储着的 Store 当前数据。因为这些数据和 Grid 的显示 数据是一一对应,所以可以通过参数(Grid Item 的行数)把 Grid 的数据映射到 Store 中,直接对 Store 里的源数据进行操作。

清单 8 中展示的是如何通过直接存取 Store 中的数据来实现对 Grid 数据的操作。程序的第一段定义了 GetItemfromStore 函数,他有两个参数一个是 Store 的名称和需要索引的行数。 有了这两个参数,就可以通过 Store._arrayOfTopLevelItems[idx] 获得对应的存储在 Store 中 Item 了。

修改 Item 比较简单,在函数 ModifyItem 中只要由 GetItemfromStore 得到 Item,然后对 Item 修改 setValue 就可以更改 Item 了。 删除 Item 也同样是由 GetItemfromStore 得到 Item,然后取出 Item 中的某个属性判断该 Item 是否符合删除条件,如果符合就在 Store 中加以删除。结合 step1 中的操作 Store 前断开连接, 操作完 Store 后恢复连接,就可以实现 Grid 的删除功能。


清单 8. 对 Store 中存储的 Item 直接操作

				

// 获得 Store 中的 Item
function GetItemfromStore(Store,idx)
{
var Item=eval(Store._arrayOfTopLevelItems[idx]);
return Item;
}

// 修改 Item
function ModifyItem()
{
for (var i=0;i<100;i++){
var Item=GetItemfromStore(modelStore,i);
modelStore.setValue(Item,'Loop',i);
}
}
// 删除 Item
function DeleteItem()
{
var deletnum=0;
var pushidx=new Array;
modelGrid._setStore(null);// 断开连接
for(var i=0;i<modelGrid.rowCount;i++){
var Item;
Item=GetItemfromStore(modelStore,i);// 获得 Item
if(Item !=null){
var sel = modelStore.getValue(Item,'Sel');// 获得 Sel 属性
if(sel==true){
deletnum=deletnum+1;
pushidx.push(Item);// 把符合条件的 Itempush 到 Array 中去
}
}
}
var Items = pushidx;
/*Store 循环删除 Item*/
if(Items.length){
for(var i=0;i<Items.length;i++){
modelStore.deleteItem(Items[i]);
}
}
modelGrid._setStore(modelStore);// 恢复连接
modelGrid._refresh();//Grid 更新视图
}


Step3. 重构 Grid 的排序方法

Grid 具有排序功能,点击表头可以实现对表格内容升序或者降序排列。每次排序的操作都是针对 Grid 加载进来的数据进行的。 排序后,当需要对数据操作时,还是先通过 Grid.getItem(idx) 获得 Item,然后依靠 Item 特有的 identifier 索引到 Store 中的真实数据, 再对数据进行修改。

然而因为“lazy loading”的存在,Grid 并没有把所有数据同时加载进来,这就导致了 Grid 排序后会出现数据获得错误和数据索引错误。 所以为了保证数据索引正确,就需要从数据源上对数据进行排序,这样才能保证 Grid 和 Store 中的数据顺序保持一致。

具体做法是先禁用 Grid 的默认 sort 方法:canSort="false"。然后重新定义 Grid.onHeaderCellMouseDown 的响应函数, 重构 sort 函数,以及更新 Grid 标题视图。这样就可以保证 Grid 的排序功能正常运行。

清单 9 展示了重新定义 onHeaderCellMouseDown 的响应函数的过程。函数定义了一个数组来存放临时变量,并且记录了表头上是否存着“全选”。 接着函数寻找记录需要排序的项目,接着设置此次排序是顺序还是逆序排列。设置完成后,就调用自定义的 sort 函数对数据进行排序。排序完后 对表头进行一定的修改,增加一个向上或者向下的箭头来标识当前表格的某列是按升序还是降序排列,便于用户识别。


清单 9. 重新定义 onHeaderCellMouseDown 的响应函数

				
//Grid.onHeaderCellMouseDown 事件就是鼠标点击表头所触发的事件。
// 我们所要做的就是把这一事件的处理函数重定向到我们自己定义的排序方法。
modelGrid.onHeaderCellMouseDown = function(e){
modelGrid._setStore(null);
var instancesArr = new Array(); // 定义一个数组存放排序临时数据
var allselRrd=dojo.byId('checkcollection').checked;// 记录表头上的“全选”状态
columnSort=e.cellIndex;
var propSort=modelGridLayout[0].cells[e.cellIndex].name; // 记录排序的项目
if(columnSort!=0){
sortAscending=!sortAscending; // 设置正向排序还是逆向排序
for(var i=0;i <modelStore._arrayOfTopLevelItems.length;i++){
instancesArr.push(modelStore._arrayOfTopLevelItems[i]);
}
sortmodelGrid(instancesArr,propSort); // 重写 sort 函数
modelStore._arrayOfTopLevelItems=instancesArr;
modelGrid._setStore(modelStore);
UpdateHeaderView(); // 更新表头
}
dojo.byId('checkcollection').checked=allselRrd;
}

清单 10 是我们根据需要重写的排序函数。在这里主要是对数据做了一个分类处理。如果排序数据是数字的话,就按照大小排列。如果排序数据是子母的话, 就先把他们转换成小写子母,然后再根据子母顺序进行排序。


清单 10. 重构 Sort 函数

				
// 根据所在列的内容的属性定制适合的 Sort 函数
function sortmodelGrid(arr,propSorter)
{
var comp=1;
var asc=1;
if(sortAscending){
asc=1;}
else{
asc=-1;}
for(var i=0;i < (arr.length);i++){
for(var j=0;j <(arr.length-1-i);j++){
var aProp=eval("arr[j]."+propSorter+"[0]");
var bProp = eval("arr[j+1]."+propSorter+"[0]");
if(IsNumber(aProp)&& IsNumber(bProp)){
// 如果是数字就直接排序
}
else{
// 如果是子母就先转换成小写再排序
aProp= aProp.toLowerCase();
bProp = bProp.toLowerCase();
}
if(aProp > bProp){
comp=1;}
else if(aProp < bProp){
comp=-1;}
else{
comp=0;}
if((comp*asc) >0){
var Itemm=arr[j+1];
arr[j+1]=arr[j];
arr[j]=Itemm;
}
}
}
}

清单 11 所做的就是在 Grid 的表头栏上增加一个向上或者向下的箭头来标识当前表格的某列是按升序还是降序排列,便于用户识别。 操作的方法主要是通过根据一些 html 属性取出表头的各列的值,对其 html 语言进行修改,插入一个箭头的符号。


清单 11. 更新 Grid 表头视图

				
// 增加一个向上或者向下的箭头来标识当前表格的某列是按升序还是降序排列,便于用户识别
function UpdateHeaderView(){
var docnObj=document.getElementsByTagName("th");
for(var i=0;i < 5;i++){
var docnObjName=modelGridLayout[0].cells[i].name;
var ret = [ '<div class="dojoxGridSortNode' ];
if(i==columnSort){
// 通过判断 sortAscending 是 true 还是 false 来认知当前是升序还是降序排列
// 根据排列顺序来修改表头的 css
ret = ret.concat([' ',(sortAscending ==true)?'dojoxGridSortUp':'dojoxGridSortDown','">
<div class="dojoxGridArrowButtonChar">',(sortAscending ==true)? '▲':'▼',
'</div ><div class="dojoxGridArrowButtonNode" ></div >' ]);
ret = ret.concat([propSort,'</div >']);
}
else{
ret.push('">');
ret = ret.concat([docnObjName,'</div >']);
}
docnObj[i].innerHTML=ret.join(" ");
}
}

图 4 是 Grid 排序后的一张效果图。可以看到 Grid 中的各项已经在 Device 列上降序排列了。Device 表头上多了一个向下的箭头,表示数据降序排列。


图 4.Grid 排序效果图

Grid 性能改善的前后对比

从下面的对比图中可以看到,经过改造后的 Grid,它在数据处理性能上的提高是非常巨大的。 在 firefox 3.5 上测试,增加 142 个项目的时间由原来的接近 1 分钟的时间缩短到 1 秒以内。说明这种提高性能的方式是行之有效的。


图 5. 未进行性能优化耗费的时间图


图 6. 性能优化后耗费的时间图


图 7 优化后添加 / 删除耗费的时间图

小结

本文解释了 Dojo Grid 控件为何在数据处理上速度较慢的原因。并且在此基础上,提供了一种提高 Dojo Grid 处理数据速度的方法, 包括如何适时与 Store 断开或建立连接,如何为适应“lazy loading”特性更改获取数据方式以及如何重构排序函数。经过实验证明,该方法性能良好。

< CMA ID: 490811 > < Site ID: 10 > < XSLT stylesheet used to transform this file: dw-article-6.0-beta.xsl >

参考资料

学习

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


我有一个网格,可以根据更大的树结构编辑小块数据.为了更容易知道用户保存了什么,我希望当用户第一次看到网格时,网格处于不可编辑状态.当用户准备好后,他们可以单击编辑按钮,这将使网格的某些部分可编辑.然后,有一个保存或取消按钮可以保存更改或还原.在大多数情况下它是有效的.但
我即将开始开发一款教育性的视频游戏.我已经决定以一种我可以轻松打包为Web,Mobiles和可能的Standalone版本的方式来实现这一目标.我不想使用Flash.因此,我确信(无论如何我会听取建议)使用JavaScript和SVG.我正在对这个问题进行大量研究,但我很难把各个部分放在一起.我知道Raphae
我正在使用带有Grails2.3.9的Dojo1.9.DojoNumberTextBox小部件–我在表单中使用–将固定格式(JavaScript基本格式)的实数值(例如:12.56)设置为HTML表单输入字段(但根据浏览器区域设置显示/编辑它们,所以用户总是看到格式正确的数字).另一方面,Grails期望输入字段根据浏览器
1.引言鉴于个人需求的转变,本系列将记录自学arcgisapiforjavaScript的学习历程,本篇将从最开始的arcgisapiforjavaScript部署开始,个人声明:博文不在传道受业解惑,旨在方便日后复习查阅。由于是自学,文章中可能会出现一些纰漏,请留言指出,不必留有情面哦!2.下载ArcGISforDe
我正在阅读使用dojo’sdeclare进行类创建的语法.描述令人困惑:Thedeclarefunctionisdefinedinthedojo/_base/declaremodule.declareacceptsthreearguments:className,superClass,andproperties.ClassNameTheclassNameargumentrepresentsthenameofthec
我的团队由更多的java人员和JavaScript经验丰富组成.我知道这个问题曾多次被问到,但为了弄清楚我的事实,我需要澄清一些事情,因为我在客户端技术方面的经验非常有限.我们决定使用GWT而不是纯JavaScript框架构建我们的解决方案(假设有更多的Java经验).这些是支持我的决定的事实.>
路由dojo/framework/srcouting/README.mdcommitb682b06ace25eea86d190e56dd81042565b35ed1Dojo应用程序的路由路由FeaturesRoute配置路径参数RouterHistoryManagersHashHistoryStateHistoryMemoryHistoryOutletEventRouterContextInjectionOutl
请原谅我的无知,因为我对jquery并不熟悉.是否有dojo.connect()的等价物?我找到了这个解决方案:http:/hink-robot.com/2009/06/hitch-object-oriented-event-handlers-with-jquery/但是没有断开功能!你知道jquery的其他解决方案吗?有jquery.connect但这个插件在我的测试中不起作用.
与java类一样,在dojo里也可以定义constructor 构造函数,在创建一个实例时可以对需要的属性进行初始化。//定义一个类mqsy_yjvar mqsy_yj=declare(null,{     //thedefaultusername    username: "yanjun",          //theconstructor   
我一直在寻找一些最佳实践,并想知道Dojo是否具有框架特定的最佳实践,还是最好只使用通用的Javascript标准?特别是我主要是寻找一些功能和类评论的指导方针?解决方法:对于初学者来说,这是项目的风格指南:DojoStyleGuide
我有’05/17/2010’的价值我想通过使用dojo.date.locale将其作为“2010年5月17日”.我尝试过使用dojo.date.locale.parse,如下所示:x='05/17/2010'varx=dojo.date.locale.parse(x,{datePattern:"MM/dd/yyyy",selector:"date"});alert(x)这并没有给我所需的日期
我正在尝试创建一个包含函数的dojo类,这些函数又调用此类中的其他函数,如下所示:dojo.provide("my.drawing");dojo.declare("my.drawing",null,{constructor:function(/*Object*/args){dojo.safeMixin(this,args);this.container=args[0];
我知道你可以使用jQuery.noConflict为jQuery做这件事.有没有办法与Dojo做类似的事情?解决方法:我相信你可以.有关在页面上运行多个版本的Dojo,请参阅thispage.它很繁琐,但似乎是你正在寻找的东西.一般来说,Dojo和jQuery都非常小心,不会破坏彼此或其他任何人的变量名.
我有一个EnhancedGrid,用户经常使用复杂的过滤器.有没有办法允许用户保存或标记过滤器,以便将来可以轻松地重新应用它?我知道我可以通过编程方式设置过滤器,但我无法预测用户想要的过滤器.谢谢!编辑:自己做了一些进展…使用grid.getFilter()返回过滤器的JSON表示,然后使用json.strin
我有这个代码:dojo.declare("City",null,{constructor:function(cityid,cityinfo){}});dojo.declare("TPolyline",GPolyline,{constructor:function(points,color){},initialize:function(map){});应该是什
我遇到的问题是我的所有javascript错误似乎来自dojo.xd.js或子模块.我正在使用chrome调试器和许多dijit功能,如dijit.declaration和dojo.parser.这有点烦人,因为它很难找到简单的错误或滑倒.我希望我可以添加一个选项,允许我的调试器在我的非dojo代码中显示选项会发生的位置.我是
我正在使用DojoToolkit数字/解析函数来处理格式化和使用ICU模式语法解析字符串.有没有人知道有可能采取任意ICU模式字符串并以某种方式使用Dojo(或其他)库将其分解为它的部分(例如,对于数字模式,它可以被分解为小数位数,数千个分组等…).我希望这样做,而不需要让我的代码密切了
我有两个看似相关的问题,访问在不同的地方定义的javascript函数.我遇到的第一个问题是调用我在firgbug或safari控制台中定义的函数.我定义了一个名为getRed的函数,如下所示:functiongetRed(row,col){//dosomethingstuffandreturntheredvalueasa
我想添加一个在Ajax调用中指定的外部样式表.我已经找到了一种方法来使用jQuery(参见下面的示例),但是我需要使该方法适应dojoJavaScript框架.JQuery示例$('head').append('<linkrel="stylesheet"type="text/css"href="lightbox_stylesheet.css">');谢谢.解决方法:一旦你
我正在尝试使用dojo.connect将onMouseDown事件连接到图像,如:dojo.connect(dojo.byId("workpic"),"onMouseDown",workpicDown);functionworkpicDown(){alert("mousedown");}类似的代码几行后,我将onMouse*事件连接到dojo.body确实完全正常工作.但是当我点击图像时