1. 程式人生 > >冷門:Dojo Gridx中,如何編寫一個module

冷門: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的官網,大家可以有一個直觀的感受:

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,讓你先弄,完事了我再弄!


講到這裡就基本完了,有什麼錯誤之處請指出來,畢竟我本不是個前端程式設計師,呵呵。