用JavaScript描述富web程序

在富web程序里,JavaScript不再是用来为网页增色的玩物,而成为真正的重点。当一个页面上有了越来越多的数据逻辑,我们如何设计才能虽多、虽杂,却不乱?

比如:要设计一个任务模块,每一个任务都可以有子任务(理论上无限子),当前任务都有一些基本描述。 如下图:

不错,这是一棵任务树。那么我们怎么设计呢?有语言:oo的重点在于抽象出不动点。那么上图什么才是不动点?

首先,相对于数据库而言,数据结构是不动的。由此我们可以抽象出Task对象,它基本对应了数据库的信息。

再者,因为数据结构是不动的,html结构数据也是不动的,我们可以抽象出TaskDom对象,他对应task对象的html描述。(动的只是css布局而已,html结构是不动的)。

Task对象和TaskDom对象互相关联。如下:

var sm = {};

sm.TaskId = 0;
sm.Task = function(parent){
	//唯一标识符
	this.id = sm.TaskId++;
	//业务属性
	this.name = "nothing";
	this.userby = "nobody";
	this.desc = "nothing";
	//节点关系
	this.parent = parent||null;
	this.children = [];
	//dom属性
	this.dom = new sm.TaskDom(this);
};
sm.Task.prototype = {
	add : function(){
		var newT = new sm.Task(this);
		this.children.push(newT);
	}
	,remove : function(){
		if(!this.parent)return false;
		var pChildren = this.parent.children;
		for(var i=0;i<pChildren.length;i++){
			var child = pChildren[i];
			if(this.id == child.id){
					pChildren.splice(i,1);
					return true;
			}
		}
		return false;
	}
	,getJson : function(pdata){
		this.dom.fillValues();
		 var data = {"name":this.name,"userby":this.userby,"desc":this.desc,children:[]};
		 pdata && pdata.children.push(data);
		 for(var i=0;i<this.children.length;i++){
			this.children[i].getJson(data); 
		 }
		 return data;
	}
};
sm.TaskDomDesc = $("#task_dom").val();
sm.TaskDom = function(task){
	this.task = task;
	this.dom = $(sm.TaskDomDesc);
	this.dom.attr("id","task-"+this.task.id)
	
	this.init();
};
sm.TaskDom.prototype ={
	init : function(){
		this.appendTo();
		this.regEvent();	
	}
	,regEvent : function(){
		var self = this;
		//child event
		self.dom.find(".control-child").first().bind("click",function(){
				self.task.add();													  
		});
		//delete event
		self.dom.find(".control-delete").first().bind("click",function(){
				self.task.remove();
				self.dom.remove();
		});
		//up event
		self.dom.find(".control-up").first().bind("click",function(){
			$(self.task.children).each(function(){
				this.dom.dom.slideToggle();
			});													   
		});		
		//task-control显示隐藏
		self.dom.find(".task-box").first().bind("mouseover",function(){
				self.dom.find(".task-control").first().show();						 
		}).bind("mouseout",function(){
				self.dom.find(".task-control").first().hide();		
		});
		//高亮
		this.dom.find(".task-box").first().bind("mouseover",function(){
				self.dom.addClass("task-highlight");		
		}).bind("mouseout",function(){
				self.dom.removeClass("task-highlight");				
		});
	}
	,appendTo : function(){
		this.dom.appendTo(this.task.parent ? this.task.parent.dom.dom : $("#tasks"));
	}
	,fillValues : function(){
		var task = this.task
		,dom = this.dom;
		
		task.name = dom.find(".task-name").first().val();
		task.userby = dom.find(".task-user-by").first().val();
		task.desc = dom.find(".task-desc").first().val();
	}
};

TaskDom中的Html信息我们隐藏在一个display=none的textarea中:

<textarea style="display:none;" id="task_dom">
    	<div class="task">
        	<div class="task-box">
        		<div class="task-head">
            		<span>task name:</span><input type="text" class="task-name"/>
                	<span class="task-control">
                		<a class="control-child">child</a>|<a class="control-delete">delete</a>|<a class="control-up">slide</a>
                	</span>
            	</div>
            	<div class="task-body">
            		<ul>
                		<li><span>user by:</span><input type="text" class="task-user-by"></li>
                    	<li><span>desc:</span><input type="text" / class="task-desc"></li>
                	</ul>
            	</div>
            </div>
        </div>
    </textarea>

Task代表任务书中的每个任务节点,TaskDom用来描述Task对象的Html存在。 于是针对上面的任务树,我们现在只关心这2个对象,而隐藏了其他所有的细节。我们只需要实例化出任务树的根节点var root = new sm.Task();其他节点均从此节点派生。 最后可以调用root.getJson()得到所有任务的相关信息。

demo下载(因为用到了JSON对象,请使用chrome,ff等浏览器)
posted @ 2011-04-13 14:20  simayixin  阅读(372)  评论(0编辑  收藏  举报