冷門:Dojo Gridx中,如何編寫一個module
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,讓你先弄,完事了我再弄!
講到這裡就基本完了,有什麼錯誤之處請指出來,畢竟我本不是個前端程式設計師,呵呵。