使用window.createPopup创建无限级跨帧下拉菜单
站点链接
RSS
先帖样子
使用层或者其他技术所实现的JS菜单不能解决的问题就是这些菜单不能跨帧,也就是说在Frame之间的时候无可奈何,所幸的是IE5+提供了createPopup这个函数,可以提供窗口的创建,使用createPopup需要注意以下几个问题:
1、函数没有任何参数
2、CreatePopup函数返回的值是新窗口的句柄,这个窗口和普通的窗口一样,所有该有的东西都有。
3、新窗口的parent属性可以对父级窗口(调用createPopup函数的窗口进行访问)
4、一个窗口只能创建一个popup窗口,新调用createPopup将会吧以前的窗口关闭。
5、新窗口的内容初始的时候是空的,没有任何内容,使用document.write和document.body.innerHTML设置值
6、窗口显示的时候调用popwindow.show函数,调用契约为 show(left,top, width, height, document.body);最后一个参数指明位置属性相对的对象
7、窗口隐藏直接调用hide函数。
8、在父级窗口中点击鼠标将会自动将popwindow隐藏。
9、销毁父亲窗口不一定销毁其创建的popwindow,前提是保存窗口句柄的对象是否被销毁。
10、使用alt-tab转换窗口的时候,有时这些新窗口会悬浮在桌面顶层,不会随IE窗口转到后台而隐藏(IE6、IE7都是)
11、新窗口的对象不能使用父窗口的CSS风格,需要手工复写
12、新窗口中的链接(Anchors)需要注意点击之后链接显示的窗口是当前的窗口,一般无效。
13、新窗口中的JavaScript出现错误的时候并不会在当前的IE状态栏中提示!
14、新窗口的CSS风格不支持expression,晕!
15、显示窗口的时候(调用show函数)必须指定窗口的位置和大小,尤其是大小,新窗口可不能自动进行缩放!
实现跨帧菜单首先确定显示方式,每一级的菜单都是显示在一个Popwindow中,如前所述,在一个窗口中只能有一个popwindow,如图显示二级菜单就无法显示了,如何解决这个问题呢?
刚才我们提到,popwindow对象本身就是一个完整的窗口对象,要解决这个问题的最直接的办法就是,下级菜单的生成有父亲菜单所在的窗口(不管是主窗口还是popwindow)调用createPopup生成,这样,各级菜单都可以拥有自己的popwindow,而且可以自动的在同级菜单中进行切换,具体的脚本如下
/*...*/
var popw=ele.document.parentWindow.window.createPopup();
/*...*/
层次结构可以构造菜单的基本样式,刚才提到,popwindow不支持CSS风格,也就是说需要手工将CSS风格写到popwindow中,写CSS风格可以使用document.write方式或者直接构造styleSheet对象然后插入rule的方式(注意,直接使用document.body.innerHTML写的style标签好像没有生效),我采用前者,主要原因是,我在主窗口中配置菜单的显示风格,而后将这些显示css风格的文本信息直接保存下来,然后对每个新窗口进行写操作,这样就可以保持每级菜单的CSS风格完全一致。
读取主窗口CSS的代码如下
for(var n=0;FrameMenuConfig.CssPrefix!=null && FrameMenuConfig.CssPrefix.length>0 && n<document.styleSheets.length;n++)
{
var sts=document.styleSheets[n];
for(var x=0;x<sts.rules.length;x++)
{
var rr=sts.rules[x];
if(rr.selectorText.indexOf(FrameMenuConfig.CssPrefix)>=0)
{
FrameMenuConfig.CssText+=rr.selectorText+"{"+rr.style.cssText+"}";
}
}
}
这里使用的是匹配FrameMenuConfig.CssPrefix的CSS风格才写入到新的窗口中。
然后涉及到菜单的数据结构的定义,这个定义比较简单,就不扯了,用膝盖也能想出来。我这边处理的时候为了防止函数被重复定义,使用了简单的类静态函数的方式进行定义。
到现在为止,我们可以画出一层一层的菜单,在每层的菜单项上挂接onmouseover处理函数就可以自动弹出下级菜单,一切看起来已经完成了。
呵呵,好像还有点东西,菜单的链接有问题,如何解决在新窗口中的Anchor链接指向的页面在我们指定的框架中显示?首先还是要强调,每个popupwindow都是一个window对象,使用parent可以取得上级的对象,我的处理方法是在主窗口中定义了一个goto(url,target)的函数,这个函数负责在主窗口中将URL正确的进行跳转,带出来的问题是,怎么让popwindw正确的调用这个函数,第一层菜单使用parent.goto,第二层菜单使用parent.parent.goto,第三层使用.....
最后一个就是解决alt-tab的问题,这个问题说起来也简单,当alt-tab处理的时候隐藏IE窗口会触发document.onfocusout事件,在这个事件中对所有的popwindow 进行关闭即可,实际测试的时候,却发现如果不对IE窗口的内容进行点击操作(鼠标划过不算),不会使得document取得焦点,也就无法触发onfocusout事件,简单的做法是生成菜单之后调用一下document.focus()函数,这个函数可能会将焦点移动,所以不是很好,但是找不到解决的办法了
没啥藏着掖着的,源代码下载test.rar (7.97 kb)
以下是测试代码,包含鼠标悬停、自动创建和右键菜单,详细请参考压缩包中的东西
<style type="text/css">
#fm_MainContainer
{
width:100%;
height:20px;
border:solid menu 1px;
background-color:ghostwhite;
padding:3px;
font-size:10pt;
color:menu;
}
#fm_MainContainer a
{
padding-left:15px;
padding-right:15px;
border-left:solid 2px #104E8B;
border-right:solid 1px #104E8B;
text-decoration=none;
color:blue;
font-size:10pt;
font-weight:bold;
background-color:;
}
#fm_MainContainer a:hover
{
text-decoration=underline;
color:red;
background-color:yellow;
}
#fm_Container
{
background-color:#E8E8E8;
height:19px;
cursor:hand;
width:150;
padding-right:3px;
border-bottom:solid 1px menu;
border-left:solid 5px #B0C4DE;
}
#fm_Container a
{
padding-left:15px;
padding-right:15px;
font-size:10pt;
text-decoration=none;
color:blue;
font-weight:normal;
}
#fm_Container a:hover
{
text-decoration=underline;
color:red;
background: url(goto.png) no-repeat;
}
</style>
<script type="text/javascript" src="../framemenu.js"></script>
<script type="text/javascript">
//系统生成的菜单如果包含有下级菜单在菜单项的左边显示的图片
FrameMenuConfig.FolderImage="leftbtn.png";
//系统菜单生成的结构为<div ><a>...</a></div>,此处设置div的显示风格,a的显示风格请附带在div中设置
FrameMenuConfig.CssPrefix="#fm_Container";
//insert函数直接插入一格记录,格式为 父亲代码、节点代码、节点显示文本、节点URL、节点的目标框架,目标框架支持_self和_blank.
FrameMenu.insert(null,"a","滚动规划");
//add2函数插入一个菜单,返回这个菜单的父亲节点的实例,格式为 节点显示文本、节点URL、节点的目标框架,目标框架支持_self和_blank.节点的ID自动生成
FrameMenu.insert(null,"b","立项管理").add2("立项1").add2("立项2");
//add函数插入一个菜单,返回这个新的菜单的实例,格式为 节点显示文本、节点URL、节点的目标框架,目标框架支持_self和_blank.节点的ID自动生成
FrameMenu.insert(null,"c","工程实施").add("工程实施1").add("工程实施1_1");
FrameMenu.insert(null,"d","验收管理").add2("测试用例").add2("测试用例");
FrameMenu.insert(null,null,"系统菜单").add2("用户管理").add2("测试用例").add2("测试用例").add("角色权限").add2("角色授权").add2("用户授权").add2("资源授权");
FrameMenu.insert(null,null,"帮助系统").add2("关于本系统").add2("退出系统");
FrameMenu.insert("a","a1","本地文件","localfile.htm","body");
FrameMenu.insert("a","a12","新浪网(弹出窗口)","http://wwww.sina.com","_blank");
FrameMenu.insert("a","a13","多级菜单");
FrameMenu.insert("a13","a13_1","新浪网(本窗口)","http://www.sina.com","_self");
FrameMenu.insert("a13","a13_2","新浪网(本窗口)","http://www.sina.com");
FrameMenu.insert("a13","a13_3","新浪网(Body)","http://www.sina.com","body");
</script>
<body topmargin="0" leftmargin="0" oncontextmenu="FrameMenuConfig.showMenu();return false;">
这个是TopFrame,Name=TopFrame
<div id="fm_MainContainer">系统菜单是安排在这里滴,嘻嘻</div>
<br/><button onmouseover="FrameMenuConfig.showMenu()">鼠标悬停方式显示完整菜单</button>
<script defer>
FrameMenuConfig.createFrameMenu("fm_MainContainer",false);
</script>
</body>