上个公司中接触的在.net平台上的一个资源分销系统,前端框架重点是大量的js代码,最近的一个资源分销是用java写的,前端框架跟之前的有一些区别。相比上一个框架这个要简单的多,主要就是html和js。
一、框架组成:
1、 大致组成的和效果图:
2、解析:
这里使用的是frameset和frame进行的框架组装。上图中不同的颜色区域代表不同的框架站位,对应相应的html或者jsp文件。
这里简单介绍一下frameset和frame的使用。frameset是frame的集合,就像table是tr和td的集合一样。rows和cols是frameset标签的两个重要属性,表示按照行进行划分还是列划分。如:
<frameset rows="67,*" cols="*" frameborder="NO" border="0" framespacing="0">
就表示框架分两行,第一行高67,第二行填充剩余空间,列进行默认划分,这里不划分列。
就像table中可以套table,frameset中也可以继续嵌套frameset。
详细的上面的框架的实现如下:
<frameset rows="67,*" cols="*" frameborder="NO" border="0" framespacing="0"> <frame src="head.html" name="topFrame" frameborder="no" scrolling="NO" noresize marginwidth="0" marginheight="0"> <frameset cols="172,*" frameborder="NO" border="0" framespacing="0" rows="*" name="workaround"> <frameset rows="34,*" cols="*" framespacing="0" frameborder="NO" border="0"> <frame src="hidden_left_frame.html" name="topFrame1" frameborder="no" scrolling="no" noresize > <frame name="leftFrame" noresize scrolling="NO" src="menu.html" frameborder=NO marginwidth="0" marginheight="0"> </frameset> <frameset rows="34,*" cols="*" framespacing="0" frameborder="no" border="0"> <frame src="toolbar.jsp" name="toolBar" frameborder="no" scrolling="no" noresize marginwidth="0" marginheight="0" id="toolBar"> <frame name="main" src="about.html" marginWidth=0 scrolling="NO" marginheight="0" noresize> </frameset> </frameset> </frameset>
简要说明:
最外层的frameset,在整体上划分为上下两行,第一行使用一个frame,src是一个head.html填充头部,即最上面的图片区域。
第二行是剩余部分,使用两个frameset集合填充,分为两列,进行竖向填充,左边的一列,再按照行进行划分为hidden_left_frame.html(红色区域)和menu.html区域。第二列也使用与第一列相同的分配方式划分为两行:toolbar.jsp(紫色)和about.html(绿色)区域。
绿色区域对应的frame的那么为main,后面的代码中会用到。
三、核心效果实现:
框架最难的的地方就是左侧动态功能菜单的生成,其他的地方基本上是写死的。下面对重点的方法进行说明,由于代码过长,在这里附上了下载的链接。
1、将系统的一个功能模块以及每个模块下的子功能定义到一个数组中,所有的样式都是针对这个数组进行的解析。
<SCript LANGUAGE=JSCRIPT> OutBarFolder1=new Array("分销商库存管理","images/admin.gif","分销商库存数量初始化","flowcard/inv_init_qty_maint.html","parent.parent.main", "images/admin.gif","分销商库存初始化确认","flowcard/inv_init_qty_confirm.html","parent.parent.main","images/admin.gif","流向单维护","servlet/flowcard/FlowCardServlet","parent.parent.main","images/admin.gif","流向单审核","flowcard/flow_card_audit.html","parent.parent.main","images/admin.gif","流向单抽查","flowcard/flow_card_spot_test.html","parent.parent.main","images/admin.gif","流向单复审","flowcard/flow_card_rehear.html","parent.parent.main","images/admin.gif","盘点结果维护","flowcard/checkvou_maint.html","parent.parent.main","images/admin.gif","盘点结果审核","flowcard/checkvou_audit.html","parent.parent.main"); OutBarFolder2=new Array("分销费管理"); OutBarFolder3=new Array("结帐管理"); OutBarFolder4=new Array("付款结算管理"); OutBarFolder5=new Array("统计报表管理","images/admin.gif","分销商级别分布图","statreport/client_level_chart.jsp","parent.parent.main","images/admin.gif","流向单录入审核报告","statreport/flow_card_audit_report.html","parent.parent.main","images/admin.gif","流向单抽查报告","statreport/flow_card_spot_test_report.html","parent.parent.main","images/admin.gif","分销商月度分销(调拨)明细表","statreport/client_detail_month_per.html","parent.parent.main","images/admin.gif","分销商库存报表","statreport/client_stock_report.html","parent.parent.main"); OutBarFolder6=new Array("基础数据管理","images/admin.gif","会计核算期间维护","basedata/fiscal_year_period_maint.jsp","parent.parent.main","images/admin.gif","物料维护","servlet/item/SearchItemServlet","parent.parent.main","images/admin.gif","分销商维护","basedata/client_maint.html","parent.parent.main","images/admin.gif","终端客户维护(医院)","basedata/temi_client_maint.html","parent.parent.main"); OutBarFolder7=new Array("系统管理","images/admin.gif","用户维护","sysmgr/user_maint.jsp","parent.parent.main","images/admin.gif","修改密码","sysmgr/password_modify.jsp","parent.parent.main"); </Script>
2、生成每个模块下的功能菜单:
function MakeItems(Folder,zorder,top) { var items=0; var folderWidth=(OB_Width-OB_BorderWidth*2); while(Folder[items+1]) items+=4; //需要改这里及下面的4; items/=4; //每一个大的功能块DIV区域,包括:图片(images/admin.gif)、图片下的文字(修改密码)、图片链接(sysmgr/user_maint.jsp)、打开链接的url窗口(parent.parent.main) document.write("<DIV id='OB_Folder"+zorder+"' style='position:absolute;left:0;top:"+top+";width:"+folderWidth+";height:"+(OB_Margin*2+items*(OB_IconsHeight+OB_LabelFontSize+OB_LabelMargin)+(items-1)*OB_ItemsSpacing)+";z-index:"+zorder+";clip:rect(0 0 0 0);'>"); //解析的时候,从1开始,而不是从0,也就是说从图片开始的,而不是每个功能模块的说明(图片上面的文字)。 for(var i=1;i<items*4;i+=4) { //图片区,并定义点击后,转向的链接和打开链接的区域 document.write("<div targetFrame='"+Folder[i+3]+"' link='"+Folder[i+2]+"' onMouseDown='OutlookLikeBar.ItemClicked(this)' onMouseUp='OutlookLikeBar.ItemSelected(this)' onMouseOver='OutlookLikeBar.OverItems(this)' onMouseOut='OutlookLikeBar.OutItems(this)' style='position:absolute;left:"+(Math.ceil((OB_Width-OB_BorderWidth*2-OB_IconsHeight)/2)-1)+";top:"+(OB_Margin+Math.ceil((i-1)/4)*(OB_ItemsSpacing+OB_LabelFontSize+OB_IconsHeight))+";cursor:hand;clip:rect(0 "+OB_IconsWidth+" "+OB_IconsHeight+" 0;width:"+OB_IconsWidth+";height:"+OB_IconsHeight+"'>"); //图片 document.write("<img src='"+Folder[i]+"'>"); document.write("</div>"); //图片下面的文字区域 document.write("<div align='center' style='position:absolute;width:160;left:0;top:"+(OB_LabelMargin+OB_IconsHeight+OB_Margin+Math.ceil((i-1)/4)*(OB_ItemsSpacing+OB_LabelFontSize+OB_IconsHeight))+";font-family:"+OB_LabelFontFamily+";font-size:"+OB_LabelFontSize+"pt;color:"+OB_LabelFontColor+"'>"); // document.write("<div align='center' style='position:absolute;width:160;left:50;top:"+(OB_LabelMargin+OB_IconsHeight+OB_Margin+Math.ceil((i-1)/4)*(OB_ItemsSpacing+OB_LabelFontSize+OB_IconsHeight))+";font-family:"+OB_LabelFontFamily+";font-size:"+OB_LabelFontSize+"pt;color:"+OB_LabelFontColor+"'>"); document.write(Folder[i+1]); document.write("</div>"); } document.write("</DIV>"); }
上面代码中是对最初定义的数组的一部分解析,每一个循环将一个模块的菜单放到动态生成的div中,值得注意的是,解析从数组的第二个元素开始。在数组的定义中,第一个元素是系统功能的模块。这里的4的意思是,每一个菜单区域由4部分组成:图片(images/admin.gif)、图片下的文字(修改密码)、图片链接(sysmgr/user_maint.jsp)、打开链接的url窗口(parent.parent.main)。
三、OutBar:
是一个对象,封装了一些方法、属性。
function OutBar(width,height,items,buttonHeight,borderWidth,slideSpeed,slideArrowValue,ArrowSlideSpeed) { this.currentFolder=1; this.currentItem=null; this.slideCount=0; this.slideStep=1; this.slideArrowValue=slideArrowValue; this.slideSpeed=slideSpeed; this.borderWidth=borderWidth; this.width=width; this.visibleAreaHeight=height-2*borderWidth-items*buttonHeight; ……………………………… this.Start=Start; this.ClipFolder=ClipFolder; this.SetArrows=SetArrows; this.HideArrows=HideArrows; this.sliding=false; this.items=items; this.started=false; this.Start(); }
页面加载的时候调用这个对象。
四、显示系统按钮和功能菜单:
<Script>
//document.all是IE专有的方法,常用于遍历窗体标签对象元素
if (document.all)
{
//OutlookLikeBar区域表示外面的最大边框区域,所有的元素都在这个区域内活动
document.write("<DIV id='OutlookLikeBar' style='position:absolute;top:"+OB_Top+";left:"+OB_Left+";width:"+OB_Width+";height:"+OB_Height+";border:"+OB_BorderWidth+" "+OB_BorderStyle+" "+OB_BorderColor+";background-color:"+OB_BackgroundColor+";z-index:0;visibility:hidden;clip:rect(0,"+OB_Width+","+OB_Height+",0)'>");
//上箭头图片
document.write("<img onMouseUp='OutlookLikeBar.ArrowSelected(this)' onMouseDown='OutlookLikeBar.ArrowClicked(this)' onMouseOver='OutlookLikeBar.OverArrow(this)' onMouseOut='OutlookLikeBar.OutArrow(this)' id='OB_SlideUp' height='"+OB_ArrowHeight+"' width='"+OB_ArrowWidth+"' src='"+OB_UpArrow+"' style='position:absolute;top:0;left:0;cursor:hand;visibility:hidden;z-index:500'>");
//下箭头图片
document.write("<img onMouseUp='OutlookLikeBar.ArrowSelected(this)' onMouseDown='OutlookLikeBar.ArrowClicked(this)' onMouseOver='OutlookLikeBar.OverArrow(this)' onMouseOut='OutlookLikeBar.OutArrow(this)' id='OB_SlideDown' height='"+OB_ArrowHeight+"' width='"+OB_ArrowWidth+"' src='"+OB_DownArrow+"' style='position:absolute;top:0;left:0;cursor:hand;visibility:hidden;z-index:500'>");
j=1;
//开始解析定义的数组,j返回的是最大数组的值,也对应系统菜单的个数
while(eval("window.OutBarFolder"+j))
j++;
i=j-1;
//从大到小的遍历。数组的最大元素是个数-1
while(i>0)
{
//Folder:每一个功能菜单项,是开头时定义的数组
Folder=eval("OutBarFolder"+i)
//window.status="Outlook-Like Bar is making folder '"+Folder[0]+"'";
if(i==1)
{
//OB_Button表示的是系统菜单
//document.write是在生成一个系统菜单如:"系统管理"、"分销商库存管理"这些值。 value='"+Folder[0]+"'赋值语句,也对应每一个数组的第一个元素
document.write("<INPUT position='UP' id='OB_Button1' onDblClick='OutlookLikeBar.FolderClicked("+i+");this.blur()' onClick='OutlookLikeBar.FolderClicked("+i+");this.blur()' TYPE='button' value='"+Folder[0]+"' style='position:absolute;top:0;left:0;width:"+(OB_Width-2*OB_BorderWidth)+";height:"+OB_ButtonHeight+";font-family:"+OB_ButtonFontFamily+";font-size:"+OB_ButtonFontSize+"pt;cursor:hand;color:"+OB_ButtonFontColor+";z-index:100'>");
//MakeItems生成的是功能菜单项内同
//最顶层的系统菜单所有区域的top属性就是OB_Button的高度。
MakeItems(Folder,i,OB_ButtonHeight);
}
else
{
//动态生成系统菜单
document.write("<INPUT position='DOWN' id='OB_Button"+i+"' onDblClick='OutlookLikeBar.FolderClicked("+i+");this.blur()' onClick='OutlookLikeBar.FolderClicked("+i+");this.blur()' TYPE='button' value='"+Folder[0]+"' style='position:absolute;top:"+(OB_Height-(j-i)*OB_ButtonHeight-OB_BorderWidth*2)+";left:0;width:"+(OB_Width-2*OB_BorderWidth)+";height:"+OB_ButtonHeight+";font-family:"+OB_ButtonFontFamily+";font-size:"+OB_ButtonFontSize+"pt;cursor:hand;color:"+OB_ButtonFontColor+";z-index:100'>");
//动态生成功能菜单
//OB_Height表示菜单高度,也就是每一个系统菜单以及下面的功能菜单的高度
//OB_ButtonHeight=22; 这里是写死的 //按钮的高度
MakeItems(Folder,i,(OB_Height-(j-i)*OB_ButtonHeight-OB_BorderWidth*2)+OB_ButtonHeight);
}
//在这里控制递归循环
i--;
}
document.write("</DIV>");
//OutlookLikeBar对象中的参数封装的是最后的大的外部边框的参数。
var OutlookLikeBar=new OutBar(OB_Width,OB_Height,j-1,OB_ButtonHeight,OB_BorderWidth,OB_SlideSpeed,OB_IconsHeight+OB_LabelFontSize+OB_LabelMargin+OB_ItemsSpacing,OB_ArrowSlideSpeed);
//all[] 是一个多功能的类似数组的对象,它提供了对文档中所有 HTML 元素的访问。
//只支持ie浏览器
document.all["OutlookLikeBar"].style.visibility="visible";
}
</SCript>
最初定义的数组的第一个元素将在这里解析成一个button,同时调用对功能菜单解析的方法,放到循环中,生成动态区域,并使用OutlookLikeBar对象封装元素对象的方法、事件、样式,如:控制箭头的位置和单击事件。
五、对理解menu.html很关键的几个变量的意义:
OB是整个系统级别菜单的外部边框以及内部对象
OB_Border是整个系统级别菜单的外部边框的宽度
OB_Button"+i:系统模块按钮区域
["OB_Folder"+i]功能菜单模块按钮div区域
OB_SlideUp向上箭头div区域
OutlookLikeBar封装所有操作的一个对象,是OB是整个系统级别菜单的外部边框以及内部的元素
六、一些重点的js语法:
clip:该属性定义了绝对(absolute)定位对象可视区域的尺寸。必须将 position 属性的值设为 absolute ,此属性方可使用。
//确定可视区域
filter = /rect\((\d*)px (\d*)px (\d*)px (\d*)px\)/;
//clip:属性定义了绝对(absolute)定位对象可视区域的尺寸。必须将 position 属性的值设为 absolute ,此属性方可使用。
var clipString=document.all["OB_Folder"+folder].style.clip;
var clip=clipString.match(filter);
outset :根据 border-color 的值画3D凸边 ;inset : 根据 border-color 的值画3D凹边
arrow.style.border="1 inset #ffffff";
七、代码连接:
如果对该框架还有核心的实现感兴趣的同学可以从这里下载源码研究,也欢迎发现问题斧正:http://download.csdn.net/detail/lmdcszh/6043785