上了高人的一堂课,回家消化了三天,写了一个DIV无限级下拉菜单。特此发布,谨以此向苦练JavaScript高手们致敬!

擒兽 2007-10-28 11:58:05
本人CSS停留在控制字体表格的阶段,所以CSS多多包含。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>简易下拉菜单</title>
<style type="text/css">
*{
font-size:12px;
}
/* 菜单容器 */
.menuFrame{
position:absolute;
}
/* 闭合菜单 */
.menuTag{
float:left;
cursor:pointer;
width:100px;
height:18px;
margin:0px 0px 0px 0px;
padding:1px 0px 1px 0px;
border: 1px solid #EEE8DD;
background-color:#F5F5F5;
text-align:center;
line-height: 150%;
color:#999999;
}
/* 打开菜单 */
.menuTagOpen{
float:left;
cursor:pointer;
width:100px;
height:auto;
margin:0px 0px 0px 0px;
padding:1px 0px 1px 0px;
border: 1px solid #EEE8DD;
background-color:#FFFFCC;
text-align:center;
line-height: 150%;
color:#0099FF;
filter:alpha(opacity=80);
-moz-opacity:0.8;
}
/* 子菜单 */
.menuItems{
cursor:pointer;
visibility:hidden;
height:0px;
text-align:left;
padding:0px 3px 0px 3px;
}
/* 二级菜单 */
.menuItemTag{
cursor:pointer;
visibility:hidden;
height:18px;
text-align:left;
padding:0px 3px 0px 3px;
}
.menuItemTagOpen{
cursor:pointer;
visibility:hidden;
height:auto;
text-align:left;
padding:0px 3px 0px 3px;
color:#000000;
}
</style>

<script type="text/javascript">
//代码看起来很痛苦,但是在Firefox上一次通过,爽!慢慢就习惯了。
//Class MenuEvent
function MenuEvent(){
this._Args = arguments;
}
MenuEvent.prototype = {
//遍历
_TraversalBindEvent:function(closeStyle,openStyle){
for(var i = 0; i<this._Args.length; i++){
var menuObj = this._GetElement(this._Args[i])
menuObj.onmouseover = this._BindEvent(menuObj,"onmouseover",closeStyle,openStyle);
menuObj.onmouseout = this._BindEvent(menuObj,"onmouseout",closeStyle,openStyle);
//偏移,让两个Div的边框重叠
if(i>0){menuObj.style.margin = "0 0 0 -1";}
}
},
//获取对象
_GetElement:function(elementID){
var menuObj = window.document.getElementById(elementID);
if(!menuObj || menuObj.tagName.toLowerCase()!="div")
{
throw "主菜单对象中至少有一个是非法对象!";
}
return menuObj;
},
//绑定事件
_BindEvent:function(menuObj,onmouse,closeStyle,openStyle){
var obj = this;
switch(onmouse){
case "onmouseover":
return function(){
obj._onMouseOverModel(menuObj,openStyle);
}
break;
case "onmouseout":
return function(){
obj._onMouseOutModel(menuObj,closeStyle)
}
break;
}
},
//事件模型
_onMouseOverModel:function(menuObj,openStyle){
//切换样式,打开菜单
menuObj.className = openStyle;
//子对象链带事件
this._ChildBindEvent(menuObj,"onmouseover");
},
//事件模型
_onMouseOutModel:function(menuObj,closeStyle){
//切换样式,关闭菜单
menuObj.className = closeStyle;
//子对象链带事件
this._ChildBindEvent(menuObj,"onmouseout");
},
//子对象跟随父对象的事件(这里并不是子对象自身触发的事件,而是父对象的事件连带触发的事件,这里还可以继续扩展子对象的样式)
_ChildBindEvent:function(menuObj,onmouse){
for(var i=0; i<menuObj.childNodes.length; i++){
var menuItemObj = menuObj.childNodes[i];
//避免非对象 和 非文档标签对象
if( !menuItemObj || !menuItemObj.tagName ){
continue;
}
//避免非div标签
if( menuItemObj.tagName.toLowerCase()!="div" ){
continue;
}
//通过父对象过滤孙子
if( menuItemObj.parentNode.id != menuObj.id ){
continue;
}
switch(onmouse){
case "onmouseover":
menuItemObj.style.height = "auto";
menuItemObj.style.visibility = "visible";
break;
case "onmouseout":
menuItemObj.style.height = "0px";
menuItemObj.style.visibility = "hidden";
break;
}
}
}
}
//Class MenuEvent - OVER

//入口程序
window.onload = function(){
//JavaScript调试最痛苦,用try语句是一个非常非常妙的调试手段,不用不知道。^_^ 用了就知道,一般人我不告诉他。
try{
//一级菜单
new MenuEvent("menuTag1","menuTag2","menuTag3")._TraversalBindEvent("menuTag","menuTagOpen");
//二级菜单
new MenuEvent("menuTag1_1")._TraversalBindEvent("menuItemTag","menuItemTagOpen");//下面两个也可以写到这句一起,都是面向对象。
//三级菜单
new MenuEvent("menuTag1_1_2","menuTag1_1_2_1")._TraversalBindEvent("menuItemTag","menuItemTagOpen");//这里方便CSS高手改进
}catch(error){
alert(error);
}
}
</script>

</head>

<body>

<div class="menuFrame">
<div id="menuTag1" class="menuTag">
一级菜单1
<div id="menuTag1_1" class="menuItems">
二级菜单↓
<div class="menuItems">  三级菜单</div>
<div id="menuTag1_1_2" class="menuItems">
  三级菜单↓
<div id="menuTag1_1_2_1" class="menuItems">
  四级菜单↓
<div class="menuItems">  五级菜单</div>
</div>
</div>
</div>
<div class="menuItems">二级菜单</div>
<div class="menuItems">二级菜单</div>
<div class="menuItems">二级菜单</div>
<div class="menuItems">二级菜单</div>
<div class="menuItems">二级菜单</div>
<div class="menuItems">二级菜单</div>
<div class="menuItems">二级菜单</div>
<div class="menuItems">二级菜单</div>
<div class="menuItems">二级菜单</div>
</div>
<div id="menuTag2" class="menuTag">
一级菜单2
<div class="menuItems">二级菜单</div>
<div class="menuItems">二级菜单</div>
<div class="menuItems">二级菜单</div>
<div class="menuItems">二级菜单</div>
<div class="menuItems">二级菜单</div>
</div>
<div id="menuTag3" class="menuTag">
一级菜单3
<div class="menuItems">二级菜单</div>
<div class="menuItems">二级菜单</div>
<div class="menuItems">二级菜单</div>
<div class="menuItems">二级菜单</div>
<div class="menuItems">二级菜单</div>
</div>
</div>

<br/>
<br/>
测试内容<br/>
1<br/>
2<br/>
3<br/>
4<br/>
5<br/>

</body>
</html>

<!--张郎:http://feb-.blog.163.com/-->
...全文
798 27 打赏 收藏 转发到动态 举报
写回复
用AI写文章
27 条回复
切换为时间正序
请发表友善的回复…
发表回复
xk2y 2007-10-30
  • 打赏
  • 举报
回复
看不懂``````
fox1999 2007-10-30
  • 打赏
  • 举报
回复
在 IE6 下顯示有很大的問題
btbtd 2007-10-29
  • 打赏
  • 举报
回复
哇蟑螂...
擒兽 2007-10-29
  • 打赏
  • 举报
回复
先抢沙发
追求标准是一件非常痛苦的事情,全部都是分离的。不知道多少豪杰为此撕过头发... ^_^
littlelam 2007-10-29
  • 打赏
  • 举报
回复
我这里看那菜单的效果好奇怪,IE6。。。
擒兽 2007-10-29
  • 打赏
  • 举报
回复
周末我再研究一下,这个还没考虑子菜单的样式事件,虽然可以实现,但是比较混乱。 需要大改结构。

其实我这种写法的目的是 便于界面设计师一目了然 他一看HTML部分就知道谁是谁的下级菜单,这样搞界面精通CSS和DIV的想怎么设计就怎么设计。子菜单可以用容器包裹起来,在容器上做文章。
gzdiablo 2007-10-29
  • 打赏
  • 举报
回复
其实只要给window.onunload事件加个语句柄就可以降低刷新后内存增加的问题 但效率非常低不建议用
而且只是清除元素因为数据绑定导致内存无法卸载的问题 但脚本里面引起的内存问题则无法解决

window.onunload = function()
{
var tags = document.getElementsByTagName("*");//获取全部标签
for(var i=0,l=tags.length;i<l;i++)//遍历全部标签 优化了for循环
for(var o in tags[i])//遍历全部属性
if(o.indexOf("on")==0)//判断属性是否以"on"开头 是否是事件柄
tags[i][o] = null;//清除事件柄的内容
}
conannb 2007-10-29
  • 打赏
  • 举报
回复
无语 强人 收藏了
gzdiablo 2007-10-29
  • 打赏
  • 举报
回复
for循环的话国外的网站上说应该
for(var i=0,l=xxx.length;i<l;i++)....

其他没什么问题,结构有点特殊..好像和我的写法有点区别........
这种结构不好评论.

jyk1970 2007-10-29
  • 打赏
  • 举报
回复
每刷新一次占用内存就多几十K !
IE 6.0.3790.1830
擒兽 2007-10-29
  • 打赏
  • 举报
回复
gzdiablo 看了你的文章,IE或IE内核的浏览器在最小化时内存调整幅度巨大,你研究得真仔细。

请教一下,上面的代码怎样改动能得到更好的效果?
gzdiablo 2007-10-29
  • 打赏
  • 举报
回复
事件模型最好是直接用闭包. 内存释放起来比较累
Croatia 2007-10-29
  • 打赏
  • 举报
回复
好大的一只蟑螂。
擒兽 2007-10-29
  • 打赏
  • 举报
回复
无语... gzdiablo暴强。
Even713 2007-10-29
  • 打赏
  • 举报
回复
代码在我这里运行得不太好,不过程序写得蛮清晰的
gzdiablo 2007-10-29
  • 打赏
  • 举报
回复
C#和java对于我来说几乎是玩具了.
C++我开发过单片机数据采集项目 但2年多没用了都生了.
C的话自从在大学时写过泥巴之外就没用过了.

javascript我有4年经验了,但以前都是DOM操作.开始OOP模式开发也只是1年多的时间.
不过已经是非常精了.也专门研究过IE的内存泄漏和内存释放问题.所以才能和你这么说.
你这样的代码大概是我半年前还没研究IE内存问题时的写法.
因为曾经看过一个贵佬的js优化建议,里面也建议说另外用一个方法去调用比较好.

确实IE存在这这样那样的问题.不过IE的标准确实比较好.FF也在慢慢的吸收IE的部分标准.
如此下去FF还真有可能超越IE.IE可能也会修正自己的bug.
擒兽 2007-10-29
  • 打赏
  • 举报
回复
gzdiablo 你学过C#或Java?
擒兽 2007-10-29
  • 打赏
  • 举报
回复
gzdiablo 你当真以前和我一样这么写的? 哈哈
擒兽 2007-10-29
  • 打赏
  • 举报
回复
其实不难发现C#和Java的一些事件都是函数指针的模式,JavaScript也不例外,实际在 onclick = "代码片段1;代码片对2;代码片段n;..."这些是明文代码 也就是函数模型,怎么样都需要实例对象。 而对象是用绳子拉着走了,绳子一断,对象也就失去了在存在的意义(所以才会丢失对象丢失了this的引用,那么程序对内存的管理原理不说大家也都明白了),现在的语言都会考虑到这一点,如果IE真这么多问题,也只能说明IE改动的地方太多,别人统一用JavaScript他就偏偏要翻版一个JSCript,而且做了很多改动,所以问题多也怪不得我们程序员。只是好多人习惯了IE反而不习惯标准了。编程进步、程序员进步,IE如果不进步,迟早会被边缘化。

这里说的内容涉及C/C++的指针 C#或Java的对象垃圾回收机制,并不是我乱说的,的确这些都是基础原理。

我晕,无非就是个下拉菜单,呵呵。 练了练刚学会不久的JavaScript模拟对象编程,再说做得也不好。
gzdiablo 2007-10-29
  • 打赏
  • 举报
回复
确实关闭了浏览器就什么都解决了。如果是大应用外加ajax交互。这里必定存在大量的数据交互。到时候就很难避免内存泄漏带来的问题。浏览速度降低是主要表现。不过一般的小应用这些可以忽略不计。
我只是提点意见。LZ的代码非常标准没什么问题。说实在我以前也是这么写的。

加载更多回复(7)

87,915

社区成员

发帖
与我相关
我的任务
社区描述
Web 开发 JavaScript
社区管理员
  • JavaScript
  • 无·法
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧