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的官网,大家可以有一个直观的感受:
http://oria.github.io/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,让你先弄,完事了我再弄!
讲到这里就基本完了,有什么错误之处请指出来,毕竟我本不是个前端程序员,呵呵。