用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等浏览器)
浙公网安备 33010602011771号