上图窗体就是基于BWF的可拖动窗体制作出来的一个alert控件,其调用代码如下:
var formhandler= form({
top:100,
width:500,
height:250,
title:" "+(_title||"提示信息"),
overflow:false,
items: [{ type: [{ typename: "div", value: "", id: "MessageICO",css:"forest_window_alert_ico",csstxt:"float:left;margin-right:20px;" },
{ typename: "div", value: "", id: "MessageTitle",text:msgtitle,csstxt:"line-height:25px;font-size:25px;width:300px;font-weight:bold;" },
{ typename: "div", value: "", id: "Message",text:msg||"",csstxt:"width:300px;" }
], csstxt: "height:145px;width:458px;margin:30px 15px 0 15px;" },
{ type: [{ typename: "button", value: " 确定 " ,css:"button_all",affair:{name:"click",fn:function(){formhandler.disappear();}} }], csstxt: "text-align:right;height:30px;margin:0px;padding-right:30px;"}]
});
其实就是挺大的JSON表达式。写到这里其实有两种实现类似效果的技术,一:只是动态一个可以拖动的框,框的主体是一个IFRAME;二:采用EXT的方式,form函数提供建立窗口的接口。
我采用了第二种,并不是说第一种如何不好,从用户接受的速度上来说第一种明显占优势,但是第一种显示的方式其实是一种跨窗体的操作,对用户的JS水平要求反而比较高,不同页面之间的刷新,数据传递之间的问题也不是很好处理,而且在实现一些很小的窗体(如上截图)的时候往往需要重新去建立一个页面。控件的传值方式与EXT的传值方式几乎相同,其中:top,width,height,title属性,是最简单也是最直观上对窗体产生样式影响的属性。而items属性,则是包含了界面上需要显示的所有元素,通过二级甚至是三级子属性的配置(几乎无需书写CSS,当然前提是控件内部封装了大量的CSS样式文件,这一点后续会说明)可以实现窗口中元素的任意排列展示方式。
首先说明一下form控件的组成:
其中当阴影层没有阴影需要显示的时候,只要在控件自带的CSS文件中修改一下CSS背景即可,阴影层会完全透明。在截图1中,窗体的深灰色半透明背景实现域可见窗口区域。
一下代码是拖动的核心代码,其中的三个参数target:即拖动的目标元素,event:当拖动事件发生后由事件源对象将事件传递进来,这里主要是兼容标准DOM浏览器,IE的Window对象中会带有一个event属性,该属性自动指向当前事件。
forest.drageDiv = dragDiv = {
drag: function (target, event, isshow) {
event = event == null ? window.event : event;
var startX = event.clientX;
var startY = event.clientY;
var origX = target.offsetLeft;
var origY = target.offsetTop;
var deltaX = startX - origX;
var deltaY = startY - origY;
var is_show;
if (isshow == null) {
is_show = null;
}
else {
is_show = isshow;
}
if (brower.ie()) {
target.setCapture();
target.attachEvent("onmousemove", moveHandler);
target.attachEvent("onmouseup", upHandler);
target.attachEvent("onlosecaptue", upHandler);
}
else
{
document.addEventListener("mousemove", moveHandler, true);
document.addEventListener("mouseup", upHandler, true);
}
stopevent(event);
stopdefault(event);
function moveHandler(evt) {
if (!evt) evt = window.event;
if((evt.clientX - deltaX)>0)
target.style.left = (evt.clientX - deltaX) + "px";
if( (evt.clientY - deltaY)>0)
target.style.top = (evt.clientY - deltaY) + "px";
stopevent(evt);
}
function upHandler(evt) {
if (!evt) evt = window.event;
if (brower.ie()) {
target.detachEvent("onlosecaptue", upHandler);
target.detachEvent("onmousemove", moveHandler);
target.detachEvent("onmouseup", upHandler);
target.releaseCapture();
}
else {
document.removeEventListener("mouseup", upHandler, true);
document.removeEventListener("mousemove", moveHandler, true);
}
stopevent(evt);
}
},
showDiv: function (value) {
var div_id = "";
if (value == null)
div_id = "hiden_div";
else
div_id = value;
var left = (parseInt(document.body.clientWidth) - parseInt(_$_(div_id).style.left)) / 2;
_$_(div_id).style.left = (parseInt(document.body.clientWidth) - parseInt(_$_(div_id).style.width)) / 2;
w(div_id).fadeIn({ speed: 0.2
, left: left
, top: 50
, direc: "up"
});
w(div_id).show();
background({});
},
closeDiv: function (Info) {
var msg = eval(Info);
var value = msg.divid;
var closeBlockage = msg.closeblockage;
var div_id = "";
if (value == null)
div_id = "hiden_div";
else
div_id = value;
w(div_id).fadeOut({
speed: 0.2
, direc: "down"
, top: _$_(div_id).style.top
, left: _$_(div_id).style.left
, callback: (function (temp) {
this.temp = temp;
return function () {
return w(temp).hidden();
}
})(div_id)
});
if (closeBlockage || closeBlockage == null) {
blockage.Close();
}
closebg();
}
}
其中所调用fadOut以及fadIn函数,就是上节中所提及的动态出现,动态消失函数,这部分的灵感来自jquery的窗口控件。
在窗口的控件区域则是一个完全不规则的区域,这个区域范围中的所有控件排列都是无规律可循,所以窗口默认情况下提供了一种行式的排列方式,及窗体结构图中的“一个控件行”元素。如果存在特殊的需求,例如:整个窗体就一行,再或者是第一行是一行文本,第二行是一个特别高大的文本框,这种需求就需要设置二、三级属性来显示窗体。
从设计上来说,form控件实质上是N个嵌套在一起的DIV元素,然后根据一些固定的或是用户自定义的CSS样式将这些DIV元素按一定的规则进行排列显示。
form表单的提交
说道窗体控件最经常然人能联想到的就是提交数据,例如新建一个人员信息,新建一笔单据,发送一笔单据等等。
在控件结构图的“控件显示区域”中包含了一个form表单元素,窗体中所有的元素:input,textarea,img等等元素都隶属于form表单,而窗体控件本身带有三个属性:
var submitFun = msg.submit; //提交的前置事件
mainform.method = msg.method || "POST";
mainform.action = msg.action || "";
其中submit是一个闭包函数,因为在实际应用中往往需要将用户输入的表单进行验证,该函数即时这个功能,如果函数返回true,则数据顺利提交,否则数据无法提交转交用户程序处理。在判断是否合法的时候有两种策略:一,必选输入项的合法性,例如在用户注册的时候用户并未输入用户名;二,逻辑性错误,例如用户输入了一个已经存在的用户名,这时提交也必须失败。第一个必选项的合法性,通过窗口的属性进行控制,如果开发人员为某个元素设定了某个特有的CSS样式(必选样式,例如红星)则在提交函数中会自动进行判断不再需要用户进行手动判断,而暴漏给用户的submit函数主要用来进行逻辑合法性验证。
子窗体
说道子窗体,在window form程序中再平常不过了,似乎在web应用中几乎没有什么情况会用到。如果你是这么想的,那就错了!在前几个项目中笔者就碰到了一次极品需求:程序需要读取一份XML来生成一个多大数百页的word文档。而XML文件本身是非常复杂的,其中数据节点潜逃了4层,公司的意思是开发一款界面化的XML配置工具。在这个项目中,首先展示在页面上的是一个数据列表,分别达标XML中的最高级数据节点,每个节点的编辑会打开一个窗口,每个窗口中包含一个TAB控件,每个子数据项就分布在这些tab页中,每个tab页中的数据又包含了自己的详细数据项。这种需求之下,子窗口就有了用武之地。
首先根据winform开发中的经验,用户在打开了子窗体后,主窗体会变得不可用。所以当子窗体弹出后,主窗体会被屏蔽掉(与页面的屏蔽层原理相同,一个半透明的IDV,同时将主窗体的关闭按钮隐藏起来。)
disabled: function (obj) {
var disabledDiv = create({ id: obj.windowID + "_disabledDiv", type: "div", classname: "forest_window_disabled_div" });
obj.CloseButton.style.display = "none";
obj.Body.appendChild(disabledDiv);
disabledDiv.style.left = obj.Body.style.left;
disabledDiv.style.top = obj.Body.style.top;
disabledDiv.style.height = parseInt(obj.Body.style.height.replace("px", "")) - 33;
disabledDiv.style.width = parseInt(obj.Body.style.width.replace("px", "")) - 3;
return this;
},
背景屏蔽层
在真实的情况之下,我们会发现好多现有的弹出框弹出以后页面背景就变灰或者被禁用了。这是因为窗体弹出后为当前网页添加了一个半透明屏蔽层的缘故,在窗体关闭的时候半透明的屏蔽层也会随之消失。
多窗体
多窗体是一个很有意思的问题,在控件刚刚开始使用的时候连笔者甚至没有意识到这个问题,因为应用场景比较简单,每次只要弹出一个窗口就OK,但是随着业务需求的深入,尤其在子窗口的应用中,多个form对象同时存在在内存中。刚开始的窗体控件采用了js的单体模式,导致了这个郁闷的问题。随后将单体模式换掉,才用了与BWF核心包forest函数相同的模式,问题解决。
本节内容就此结束。