表单设计器设计思路
1.页面布局
分为3个部分(设计器图片已上传)
(1)组件,用来画表单的基础工具,可以用Ext的tree实现。
(2)设计区域,就是一个配上背景图片的div。
(3)右侧属性栏,每个组件都有自己的属性配置,可以用Ext的PropertyGrid来实现。
2.组件拖拽到设计区
可以通过ext自带的拖拽功能很容易实现。设定拖拽源为tree,拖拽目标位设计区div,代码如下:

dropTarget = new Ext.dd.DropTarget(Ext.getDom('pageId'), {
        ddGroup: 'DDGroup',
        notifyEnter: function (ddSource, e, data) {
			//拖拽过程中执行
        },
        notifyDrop: function (ddSource, e, data) {
            //鼠标放开之后执行,ddSource拖拽源,e事件
            return (true);
        }
    });

3.当拖拽到设计区之后需要创建对象


定义一个全局文档对象var domObj = {};//临时存放页面所有元素的对象集合,key为标签的id,value为对象引用。


在notifyDrop函数里判断拖拽的组件类型来实例化相对应的对象,然后分别添加到设计区内和domObj中。


添加到设计区为了达到显示效果,添加到文档对象中为了读取属性回显和保存的用途。


4.面向对象设计


在这里需要以OO的思路来处理,便于维护和扩展,将所有组件的公用部分属性抽象到超类中,每个组件都有自己的类定义,代码如下:


//超类组件的公共属性


//*********************继承通用方法***********************
	function extend(sub , sup){//sub子类,sup父类
		var F = function() {},		
			subclassProto,//子类的原型对象
			superclassProto = sup.prototype;//把父类的原型对象交给了superclassProto变量
		F.prototype = superclassProto;	
		subclassProto = sub.prototype = new F();	
		subclassProto.constructor = sub;		
		sub.superclass = superclassProto;
		if (superclassProto.constructor === Object.prototype.constructor) {
			superclassProto.constructor = sup;
		}	
	};
	function BaseObject(id,top,left,width,height,type){
		this.id = id;
		this.top = top;
		this.left = left;
		this.width = width;
		this.height = height;
		this.type = type;
	}
	//*********************标签***********************
	function Label(id,top,left){
		BaseObject.call(this,id,top,left,'40','20','label')
		this.value = '标签';
		this.color = '';
	}
	extend(Label,BaseObject);//继承超类
	Label.prototype.toHtml = function () {
		var obj = $("<label style='Z-INDEX: 1;POSITION: absolute;'></label>");
		obj.attr("id", this.id);
		obj.text(this.value);
		addEvent(obj,this);//添加一些事件,略...
		return obj;
	}



每次向设计区添加组件都是通过new对象,然后调用toHtml方法来添加到div中。


5.拖拽原理


通过拖拽改变div位置和大小,当鼠标按下时mousedown绑定移动事件mousemove,当鼠标抬起时mouseup接触绑定的事件。


这样一来当按下时候随着鼠标的移动不断的改变对象坐标属性就可以达到拖拽的效果了。可以考虑把拖拽函数写成jquery插件形式便于调用。


代码如下:


this.mousedown(function (e){
	var x = e.clientX - 160;
	var y = e.clientY - 27;
	var right = this.offsetLeft + this.offsetWidth;
	var bottom = this.offsetTop + this.offsetHeight;
	if((x<right&&x>=right-3)&&(y>=this.offsetTop&&y<=bottom)&&type!='Yline'){
		var domObj = {};
		domObj.x = x - this.offsetWidth;
		domObj.y = y - this.offsetHeight;
		domObj.dom = this;
		$(document).bind("mousemove", {domObj: domObj}, updateWidth).bind("mouseup", mouseUp);
		if(typeof(fn)!='undefined'){
			$(document).bind("mousemove", updatePosition).bind("mouseup", {domObj: domObj, dragType:'width'}, fn);
		}
	}
	else if((y<bottom&&y>=bottom-3)&&(x>=this.offsetLeft&&x<=right)&&type!='Xline'){
		var domObj = {};
		domObj.x = x - this.offsetWidth;
		domObj.y = y - this.offsetHeight;
		domObj.dom = this;
		$(document).bind("mousemove", {domObj: domObj}, updateHeight).bind("mouseup", mouseUp);
		if(typeof(fn)!='undefined'){
			$(document).bind("mousemove", updatePosition).bind("mouseup", {domObj: domObj, dragType:'height'}, fn);
		}
	}  
	else{
		for(var i=0;i<domArray.length;i++){
			domArray[i].x = x-parseInt($(domArray[i].dom).css('left'));	
			domArray[i].y = y-parseInt($(domArray[i].dom).css('top'));
		}
		$(document).bind("mousemove", updatePosition).bind("mouseup", mouseUp);
		if(typeof(fn)!='undefined'){
			$(document).bind("mousemove", updatePosition).bind("mouseup", {dragType:'move'}, fn);
		}
	}
	//防止默认事件发生 
	e.preventDefault();
});	
	//鼠标抬起时,解除拖拽效果的绑定
	function mouseUp(e){
		$(this).unbind("mousemove",updateWidth).unbind("mousemove",updateHeight).unbind("mousemove",updatePosition).unbind("mouseup");            
	}

6.多选和键盘事件


以按住ctrl多选为例,需要定义2个全局对象。


var keyFalg = false;//判断是否按下ctrl键
	var domArray = [];  //存放当前选中的对象数组
	//绑定整个文档键盘事件,判断键盘是否按下
	$(document).keydown(function(event){
		keyFalg = true;
	});
	$(document).keyup(function(event){
		keyFalg = false;
	});

当对象点击事件被执行时判断keyFalg状态,来决定数组内容。


当执行拖拽等操作时,来通过数组对象循环改变每个对象属性值来达到同时拖拽多个对象的效果。


7.保存


分开两种保存,html和json或xml。


html用于给填表单的人使用,json数据用于给开发人员修改表单用。


保存html通过jquery的html()方法来实现。


保存json通过Ext.util.JSON.encode()方法来实现。


源码地址:[url]http://item.taobao.com/item.htm?spm=a1z10.5.w4002-5308542543.10.tBIcCP&id=37074279659[/url]


图片效果在附件中。。。


[img]http://dl2.iteye.com/upload/attachment/0075/6812/6882505a-1716-3c4a-a7d9-20b91853506d.jpg[/img]