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',其中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,让你先弄,完事了我再弄!
讲到这里就基本完了,有什么错误之处请指出来,毕竟我本不是个前端程序员,呵呵。