跨帧 (frameset,freame,iframe) 的无限级菜单
大家都知道在IE中,存在frameset,freame,iframe三种帧元素,他们在布局中运用广泛,而且也很实用,但是有时候使用起来还是有一些小麻烦。如你是做相关框架或者是企业管理软件的,需要使用到它来布局,那他的层级是最高的,也就是说他的z-index是最高的,那就会带来一个问题,假如你的ifream上面可能会出现诸如菜单,悬浮div的时候,那他们将会被帧覆盖。这样降带来用户无法接受的体验,可以解决的方案很多,但是如果你确实已经在用帧并且无法替代它(出于开发时间或者成本),那么我们不妨来学习制作一下跨帧的下拉菜单,仅限IE,其他浏览器不再考虑范围。
首先我们采用的方案就是IE下的window.createPopup,它是弹出对话框,当用户焦点退出对话框的时候,对话框会自动消失,我们也可以再它消失的时候释放一些资源等。但是他也会带来几个问题,需要我们去考虑:
1. 我们需要写一些javascript来实现下拉菜单,这需要对javascript有一点了解。
2. popup window 是不支持父窗口css导入,这需要我们去用javascript动态写入,
好像CSS风格也不支持expression。
3. popup window初始化的时候是不可见的,需要调用popupwin.show()来显示窗口,这点我们可能好好利用。
好了下面我们看一个列子:当点击按钮时会出现一个弹出框。
<HTML>
<HEAD>
<TITLE>Popup Example</TITLE>
<SCRIPT LANGUAGE="JScript">
var oPopup = window.createPopup();
function ButtonClick()
{
var oPopBody = oPopup.document.body;
oPopBody.style.backgroundColor = "lightyellow";
oPopBody.style.border = "solid black 1px";
oPopBody.innerHTML = "Click outside <B>popup</B> to close.";
oPopup.show(100, 100, 180, 25, document.body);
}
</SCRIPT>
</HEAD>
<BODY>
<BUTTON οnclick="ButtonClick()">Click Me!</BUTTON>
</BODY>
</HTML>
接下来我们一起来分析怎样来实现无限级跨帧菜单,我想第一步分析下数据结构,以便我们来用基于对象的javascript来实现menu Object。很容易想到它就是tree结构。
属行 | 描述 | 值描述 |
Id | menuitem 的唯一标示 | 可以任意定义,但是得保证唯一 |
index | 序列,用与所有menuitem排序,扩展功能 | 一般从0开始不断增加 |
title | menuitem标题,描述 | 任意字符串 |
properties | 属性集合,扩展使用 | 存储任意其他信息 |
parentId | 父menuitem的Id, | |
children | menuitem的子按钮 | |
classStyle | 常量字符串,用于模拟typeof | |
icon | 按钮图标,扩展用 | |
url | 按钮链接地址 |
还有一个target属性,指定我们以怎样的方式打开我们的新的链接,如_self, _blank,或者其他frame的引用。
MenuItem = function(id ,index,parentId, title,icon,url,toTarget)
{
this.defaultIcon = "menu.gif";
this.id =id;
this.index = (index!=null && parseInt(index)>0) ? parseInt(index): 0 ;
this.title = title;
this.properties = new Array();
this.parentId = parentId;
this.children = new Array();
this.classStyle ="MenuItem";
this.icon = (icon!=null && icon.length>0)? icon : this.defaultIcon;
this.url = (url!=null && url.length>0)? url:"";
this.toTarget = toTarget;
};
以上就是类似与树的节点,那下面就是我们树本身的一些操作和封装,比如menu的样式css,添加主菜单和子菜单的基本方法:
1. Menubar 的结构:
PopMenu = function (cssFile, normalClass,hotClass,menuClass,menuWidth,menuHeight)
{
this.defaultMenuWidth = 80;
this.defaultMenuHeight = 25;
this.cssFile = cssFile;
this.normalClass = normalClass;
this.hotClass = hotClass;
this.menuClass = menuClass;
this.menuWidth = (menuWidth && menuWidth!=null && parseInt(menuWidth) >0)? parseInt(menuWidth):this.defaultMenuWidth;
this.menuHeight = (menuHeight && menuHeight!=null && parseInt(menuHeight) >0)? parseInt(menuHeight):this.defaultMenuHeight;
this.menus = new Array();
this.popWin =window.createPopup();
this.popWin.document.createStyleSheet(this.cssFile);
if(window.navigator.appName.indexOf("Microsoft")>=0) this.appName = "IE";
else if(window.navigator.appName.indexOf("Netscape")>=0) this.appName="NS";
else this.appName ="OT";
appName = this.appName;
};
2.初始化菜单
PopMenu.prototype.initTopMenu = function (divId)
{
popMenuInstant = this;
var target = null;
if(divId!=null && divId.length>0)
{
target = document.getElementById(divId);
if (target==null ) {
alert("could not find the menu element!");
return;
}
}
var len = this.getTopMenusLength();
target.style.width= (parseInt(this.getMenuWidth())*len+ 10 * len);
target.style.height= parseInt(this.getMenuHeight()+4);
if(len>0)
{
var menutable = document.createElement("table");
var menuContent ="";
for(var i=0;
i<len ;
i++)
{
var tempMenu = this.getTopMenus()[i];
var url = (tempMenu.getURL()!=null && tempMenu.getURL().length>0)?tempMenu.getURL():".";
menuContent+=("<td id ='"+tempMenu.getMenuId()+"' class='"+this.normalClass+"' " +
" οnmοuseοver='javascript:_onMenuItemFocus.call(this);' " +
" onmouseout ='javascript:_onMenuItemNormal.call(this);' " +
" >"+tempMenu.getMenuTitle()+"</td>");
}
target.innerHTML =
"<table class='menuTable'>"+
"<tr>"+
menuContent+
"</tr>"+
"</table>";
}
};
3. 创建菜单:
PopMenu.prototype.addMenuItem = function(id ,index,title,icon,url)
{
var menuItem = new MenuItem(id ,index,null, title,icon,url,null);
this.menus.push(menuItem);
};
4. 创建子菜单:
PopMenu.prototype.addSubMenuItem = function(id ,index,parentId, title,icon,url,toTarget)
{
if(parentId ==null ||parentId.length<=0)
{
this.addMenuItem(id, index, title, icon,url);
}
else
{
var parent = this.findMenu(parentId);
var menuItem = new MenuItem(id ,index,parentId, title,icon,url,toTarget);
parent.addChild(menuItem);
}
};
4.点击按钮,创建popup 子菜单
_createSubMenu =function(menuId)
{
var menu = popMenuInstant.findMenu(menuId);
var parentMenu = null;
if(menu.getParentId()!=null && menu.getParentId().length>0 )
parentMenu = popMenuInstant.findMenu(menu.getParentId());
var children = menu.getChildren();
if(children.length && children.length>0)
{
var width = popMenuInstant.menuWidth;
var height = ((parseInt(children.length)+1) * popMenuInstant.menuHeight);
var htmlStr = "<div style=\"width:"+(parseInt(width))+"px;\" >"
+ "<table class=\"menuTable\" >";
for (var i = 0; i < children.length; i++)
{
var menu = children[i];
if(typeof menu == "object" && menu.getClassStyle()=="MenuItem")
{
htmlStr += "<tr style=\"width:"+(parseInt(width))+"px;\"><td id=\""+menu.getMenuId()+"\"" +
" class=\"" +popMenuInstant.normalClass+"\""+
" οnmοuseοver=\"javascript:window.top._onMenuItemFocus.call(this);" +"\""+
" οnmοuseοut=\"javascript:window.top._onMenuItemNormal.call(this);" +"\""+
" οnclick=\"javascript:window.top._onMenuItemClick.call(this);" +"\""+
"><div>" +menu.getMenuTitle()+"</div></td></tr>";
}
}
htmlStr += "</table>";
htmlStr += "</div>";
var popWin =null;
if(parentMenu!=null&&parentMenu.getMenuId()!=null && parentMenu.getMenuId().length>0 )
{
popWin = this.document.parentWindow.createPopup();
popWin.document.createStyleSheet(popMenuInstant.cssFile);
popWin.document.body.innerHTML = htmlStr;
if(!popWin.isOpen)
{
popWin.show ((parseInt(this.clientLeft)+parseInt(this.clientWidth)),
(parseInt(this.clientTop)+parseInt(this.clientHeight)), width, height, this);
}
else
{
popWin.hide();
popWin.show ((parseInt(this.clientLeft)+parseInt(this.clientWidth)),
(parseInt(this.clientTop)), width, height, this);
}
}
else
{
popWin = window.top.createPopup();
popWin.document.createStyleSheet(popMenuInstant.cssFile);
popWin.document.body.innerHTML = htmlStr;
if(!popWin.isOpen)
popWin.show (-5, parseInt(this.offsetHeight)+2, width, height, this);
else
{
popWin.hide();
popWin.show (-5, parseInt(this.offsetHeight)+2, width, height, this);
}
}
}
};
这样我们就可以很简单的来实现页面的东西了:iframe就是为了测试是不是可以跨帧。
<div id ="popmenu"></div>
<iframe name="mainFreame" id="mainFreame" width="1024" height="800"></iframe>
是不是有点操作对象的感觉了:
<script type="text/javascript">
var popMenu = new PopMenu("css/menu.css","normalMenu","focusMenu","menu","200","25");
popMenu.addMenuItem("menu1", 1, "Menu 1", "file.gif","");
popMenu.addMenuItem("menu2", 2, "Menu 2", "file.gif","");
popMenu.addMenuItem("menu3", 3, "Menu 3", "file.gif","");
popMenu.addMenuItem("menu4", 4, "Menu 4", "file.gif","");
popMenu.addSubMenuItem("menu21", 1, "menu2", "Menu 2-1", "file.gif","http://www.hao123.com","_blank");
popMenu.addSubMenuItem("menu22", 2, "menu2", "Menu 2-2", "file.gif","http://www.hao123.com","_self");
popMenu.addSubMenuItem("menu211", 1, "menu21", "Menu 2-1-1", "file.gif","http://www.hao123.com","mainFreame");
popMenu.addSubMenuItem("menu2111", 1, "menu211", "Menu 2-1-1-1", "file.gif","http://www.163.com","mainFreame");
popMenu.addSubMenuItem("menu2112", 2, "menu211", "Menu 2-1-1-2", "file.gif","http://www.163.com","mainFreame");
popMenu.addSubMenuItem("menu21121", 1, "menu2112", "Menu 2-1-1-2-1", "file.gif","http://www.163.com","mainFreame");
popMenu.addSubMenuItem("menu21122", 2, "menu2112", "Menu 2-1-1-2-2", "file.gif","http://www.163.com","mainFreame");
popMenu.addSubMenuItem("menu221", 2, "menu22", "Menu 2-2-1", "file.gif","http://www.csdn.com","mainFreame");
popMenu.addSubMenuItem("menu222", 2, "menu22", "Menu 2-2-1", "file.gif","http://www.csdn.com","mainFreame");
popMenu.addSubMenuItem("menu31", 1, "menu3", "Menu 3-1", "file.gif","http://www.baidu.com","mainFreame");
popMenu.addSubMenuItem("menu32", 2, "menu3", "Menu 3-2", "file.gif","http://www.baidu.com","mainFreame");
popMenu.addSubMenuItem("menu33", 2, "menu3", "Menu 3-3", "file.gif","http://www.baidu.com","mainFreame");
popMenu.initTopMenu("popmenu");
</script>
效果图:
点击效果:
完成,本人只是在探讨实现方法和过程,有可能程序不够完善,读者见谅。如果想下载源代码,
请链接:http://download.youkuaiyun.com/detail/wodetiankong516/4493907