冷门: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',其中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,让你先弄,完事了我再弄!


讲到这里就基本完了,有什么错误之处请指出来,毕竟我本不是个前端程序员,呵呵。

相关文章

我有一个网格,可以根据更大的树结构编辑小块数据.为了更容易...
我即将开始开发一款教育性的视频游戏.我已经决定以一种我可以...
我正在使用带有Grails2.3.9的Dojo1.9.DojoNumberTextBox小部...
1.引言鉴于个人需求的转变,本系列将记录自学arcgisapiforja...
我正在阅读使用dojo’sdeclare进行类创建的语法.描述令人困惑...
我的团队由更多的java人员和JavaScript经验丰富组成.我知道这...