DOJO 是一个开源的 Javascript 开发框架,最近版本是1.9,类似的还有大名鼎鼎的Jquery, YUI 等等。 因为工作的原因最近接触了这个框架,奇怪的是好像在业界DOJO并不流行,网上资料也较少,只有IBM在大力的推动,看来效果也是差强人意,感觉是个冷门的玩意。经过几天的接触觉得这个DOJO还不错,有很多值得推荐的地方。
1. 模块化:Dojo的库都做成了一个一个的模块,类似java中的package,需要的时候“import” (require)进来,不需要就不引用。
2. OO: 作为一个java程序员我觉得很亲切,在dojo中OO无处不在,感觉是在坚决的走面向对象,模拟的也好,稍显别扭也好,毕竟使用的是javascript,已经难能可贵了。
接着说gridx, 这是基于dojo框架做的一个datatable的控件。 说是一个控件还真是委屈它了,其实它功能相当的庞大,习惯以后也比较好用,效果也是相当的炫。
这个链接是gridx的官网,大家可以有一个直观的感受:
gridx 的module:
在gridx中,基本上所有的功能都是在module中实现的,有很多的build-in 的module。这些module又分为核心module的和补丁module。 核心(core) module实现的gridx的核心功能,比如Header, body, scroller 等等,是在new gridx的时候就被自动加载的。 其它的是非核心(plugin) module, 他们是on-demand的, 加载就有,不加载就没的。看一个典型的生成grid的代码:
var data = [];
var store = new Memory({
idProperty : "id",
data: data
});
var structure = [
{field: "id", name: "Element"},
{field: "value", name: "Value (Double click to edit)", editable: true}
];
var modules = [
"gridx/modules/Edit",
'gridx/modules/CellWidget',
"gridx/modules/HiddenColumns"
];
var grid = Grid({
id: "grid",
cacheClass: Cache,
store: store,
structure: structure,
autoHeight: true,
modules: modules
});
grid.placeAt("gridDiv");
grid.startup();
注意到数组modules了吗,在这个例子中import了三个module:"gridx/modules/Edit",'gridx/modules/CellWidget' 和"gridx/modules/HiddenColumns"。
Module 的生命周期:
Module的生命周期包括:constructor(), preload(), and load() 还有一个distory(), 最后一个有点不确定,有知道的同学请告之!
对应这些阶段分别为:
1. constructor(): 生成mode, 这个mode是另外一个话题,对了,就是你想的那样MVC中的M,不要质疑为啥javascript框架出现了MVC,我也很惊叹!
并且new 出所有的modules
在这个阶段,所有的modules都被new出来的,但是并不知道彼此的存在,没法使用其他module的功能。
2. preload():
在此阶段,所有module的constructor()方法都已经执行完成,可以初步使用它们提供的功能(这些功能必须是在constructor()完成后就能使用的)
3. load():
所有的module的preload()方法执行完成,本module依赖的module们已经完全加载完毕,可以使用任何它们提供的功能。
4. destory():
不十分确定,应该是用来销毁本module内创建的object。
好了,基本清晰了,大部分module都有以上四个function, 当然是optional的,有的话就会被调用,没有就算了。 像不像使用java在实现“模板模式” ?
Module的依赖:
module可以依赖其他module,有三种层次的依赖:
1. forced: ["module name"], 本module不会load,除非这种依赖的module load完成
2. required: ["module name"] , 本module需要,但是不着急,可以在任何时候load。
3. optional: ["module name"], 如果括号中的module存在,那么请在本module之前load,不存在就算了。
我们看一个例子:
define([
"dojo/_base/array",
"dojo/dom",
"dijit/form/CheckBox",
"dojo/_base/declare",
"dojo/_base/event",
"dijit/registry",
"dojo/dom-construct",
"dojo/dom-class",
"dojo/keys",
"../core/_Module",
"./HeaderRegions"
], function(array, dom, CheckBox, declare, event, registry, domConstruct, domClass, keys, _Module){
return declare(_Module, {
name: 'headerCheckbox',
forced: ['header','sort'],
preload: function(){
},
load: function(){
var t = this,
g = t.grid;
var onChanged = function(e){
var colId = this.id;
array.forEach(g._columns, function(col){
if(colId == col.id){
var id = col.field;
g.store.data.forEach(function(item, i){
var tmpItem = item;
tmpItem[id] = e;
g.store.put(tmpItem, {overwrite : true});
});
}
});
g.model.clearCache();
g.body.refresh();
}
array.forEach(g._columns, function(col){
if(col.id != "1"){
var header = g.header.getHeaderNode(col.id);
var checkbox = new CheckBox({
id: col.id,
checked: false,
onChange: onChanged
});
var outerDiv = domConstruct.toDom("<div style='display: inline-block;margin-right:10px'> </div>");
checkbox.placeAt(outerDiv);
checkbox.startup();
domConstruct.place(outerDiv, header, "last");
this.domNode = outerDiv;
}
});
},
destory: function(){
domConstruct.destroy(this.domNode);
}
});
});
首先,这个例子是可以用的,它在除了第一列以外的没有header中添加了一个checkbox,并且在这个checkbox没选中的时候选中本列中每一个cell中的checkbox(前提是每个cell中都只是个checkbox,比较没法复用,可以重写onChange事件去实现自己的功能)。
具体就不讲了,大家可以注意到上面提到的四个function,这个例子中有三个(其实只有两个)。
另外在讲一点:
大家可以注意到这个例子的依赖有点奇怪:forced: ['header','sort'], 其中header是能理解的,那么为什么要依赖“sort” 还是force级别的依赖,一提起来就一肚子火啊,坑爹啊有没有!大家可以看看module sort的源码:
_initHeader: function(colId){
var g = this.grid,
headerCell = g.header.getHeaderNode(colId),
col = g.column(colId, 1),
sb = [];
if(col.isSortable()){
sb.push("<div role='presentation' class='gridxArrowButtonNode'>",
"<div class='gridxArrowButtonCharAsc'>▴</div>",
"<div class='gridxArrowButtonCharDesc'>▾</div>",
"</div>");
headerCell.setAttribute('aria-sort', 'none');
}
sb.push("<div class='gridxSortNode'>", col.name(), "</div>");
headerCell.innerHTML = sb.join('');
},
注意看最后这句,直接把header中的innerHTML给完全替换掉了,可是写这段的大哥有没有想想,如果别的module也修改了header的子孙节点这里就完全被覆盖掉了,并且这段代码是在load()函数中被调用的。本人就吃了这个亏,怎么办呢,不能改人家已经发行的源码吧,只要剑走偏锋:
所以在force中加了这个module,让你先弄,完事了我再弄!
讲到这里就基本完了,有什么错误之处请指出来,毕竟我本不是个前端程序员,呵呵。