posts - 283,  comments - 6275,  trackbacks - 107

    其实这个控件的核心基本都在JS上,而相关的数据绑定和显示却非常简单。而需要说明的是在Discuz!NT的1.0
和2.0正式版,这个控件做过一些调整,当然改动也基本上是在JS上,今天给大家的源码是1.0正式版的代码,虽然
有些“旧”,但程序本身的思想没变,大家只要明白了这里的源码,有了这碗酒垫底,相信再看即将开源的2.0代码,
就会一目了然了。

    好了,废话到此,马上开始今天的话题!

    先请大家看一下这个控件运行时的效果图:

    效果图1:
 
         

    效果图2: 
  
    首先将相应的C#代码放出来:

    

  1Property ScriptPath
 21
 22

 23    Property ImageUrl

 45
 46

 47    Property CssPath

 67
 68

 69    Property XmlFileFullPathName

 89
 90    protected override void OnPreRender(EventArgs e)

119
120 
/// <summary> 
121 ///
 将此控件呈现给指定的输出参数。
122 /// </summary>

123 /// <param name="output"> 要写出到的 HTML 编写器 </param>

124 protected override void Render(HtmlTextWriter output)
125 
{
126
         
127  output.Write("<div class=\"sdmenu\">\r\n"
);
128
  
129  System.Data.DataSet dsSrc = new
 System.Data.DataSet();
130  dsSrc.ReadXml(Page.Server.MapPath(this
.XmlFileFullPathName));
131

132  int count=0
;
133  foreach(System.Data.DataRow dr in dsSrc.Tables[0
].Rows)
134  
{
135   输出主菜单

153
154   输出子菜单

193
194   //打印分割符

195   output.Write("<div class=\"splitter\">&nbsp;</div>\r\n");
196   count++
;
197   }

198
199   output.Write("</div>\r\n"
);   
200  }

201 }
202

203
    
204

205

    上面的代码因为太简单,就不多做介绍了。而XML的结构如下:


    其中的submain表(这里暂且这样说)的menuparentid(子菜单的父menuid),是关联mainmenu表的menuid,这样就能够这
这两个表有一个主从结构了。当前如果将这两个表合成“一个”也可以,前提是要减少数据冗余,因为mainmenu表里是不
包含link(点击子菜单跳转地址),frameid(子菜单跳转的frameid)这样的信息的。
   
   
    最后要说明的是这个控件的JS,代码如下(详情见注释):
    

  1   
  2var remember = false//记录当前菜单状态,当下次访问时使用

  3var contractall_default= 1//系统菜单项状态  1:只显示第一项  2:展开所有项   3:收缩所有的菜单项
  4
  5var menu, titles, submenus, arrows, bypixels; //定义指定的菜单数组变量
  6var heights = new Array();
  7var speed=10;  //加载菜单项的速度 

  8
  9var n = navigator.userAgent;
 10

 11if(/Opera/
.test(n)) 
 12
{
 13    bypixels = 2
;
 14}

 15else if(/Firefox/.test(n)) 
 16
{
 17    bypixels = 3
;
 18}

 19else if(/MSIE/.test(n)) 
 20
{
 21   bypixels = 2
;
 22}

 23
 24

 25//展开所有菜单项

 26function slash_expandall()
 27
{
 28    if (typeof menu!="undefined"
)
 29    
{
 30     for(i=0; i<Math.max(titles.length, submenus.length); i++
)
 31     
{
 32      titles[i].className="title"
;
 33      arrows[i].src = imgpath+"/top_level_ico1.gif"
;
 34      submenus[i].style.display=""
;
 35      submenus[i].style.height = heights[i]+"px"
;
 36     }

 37    }

 38}

 39
 40

 41//收缩所有菜单项

 42function slash_contractall()
 43
{
 44    if (typeof menu!="undefined"
)
 45    
{
 46     for(i=0; i<Math.max(titles.length, submenus.length); i++
)
 47     
{
 48      titles[i].className="titlehidden"
;
 49      arrows[i].src = imgpath+"/top_level_ico2.gif"
;
 50      submenus[i].style.display="none"
;
 51      submenus[i].style.height = 0
;
 52     }

 53    }

 54}

 55
 56
 
 57

 58//初始化函数

 59function init(){
 60    menu = getElementsByClassName("sdmenu""div", document)[0
];
 61    titles = getElementsByClassName("title""span"
, menu);
 62    submenus = getElementsByClassName("submenu""div"
, menu);
 63    arrows = getElementsByClassName("arrow""img"
, menu);
 64    for(i=0; i<Math.max(titles.length, submenus.length); i++

 65    
{
 66        titles[i].onclick =
 gomenu;
 67        arrows[i].onclick =
 gomenu;
 68        heights[i] =
 submenus[i].offsetHeight;
 69        submenus[i].style.height = submenus[i].offsetHeight+"px"
;
 70        /*alert(i); */

 71 
 72        if(i>0
)
 73        
{
 74           titles[i].className="titlehidden"
;
 75        arrows[i].src = imgpath+"/top_level_ico2.gif"
;
 76        submenus[i].style.display="none"
;
 77        submenus[i].style.height = 0
;
 78        //alert('123');

 79     }

 80 }

 81 
 82    if
(remember)
 83 
{
 84
     restore();
 85 }

 86 
 87 //根据菜单项状态设置,显示菜单

 88 switch(contractall_default)
 89 
{
 90     case 1

 91     
{
 92         break
;
 93     }

 94     case 2:
 95     
{
 96         slash_expandall();break
;
 97     }

 98     case 3:
 99     
{
100
         slash_contractall();
101     }

102     default:
103     
{
104         break
;
105     }

106 }

107}

108
109//存储菜单项状态

110function restore() {
111    if(getcookie("menu"!= null
{
112        var hidden = getcookie("menu").split(","
);
113        for(var i in hidden) 
{
114
           
115            titles[hidden[i]].className = "titlehidden"
;
116            submenus[hidden[i]].style.height = "0px"
;
117            submenus[hidden[i]].style.display = "none"
;
118            arrows[hidden[i]].src =imgpath+"/top_level_ico2.gif"
;
119         }

120    }

121}

122
123//定向到指定的菜单项进行相应操作

124function gomenu(e)
125
{
126    if (!
e)
127    
{
128       e = window.event
;
129    }
   
130
    
131    var ce = (e.target) ?
 e.target : e.srcElement;
132
    
133
    var sm;
134
    
135    //找到当前菜单项在数组中的位置,用于下面显示或隐藏判断

136    for(var i in titles) 
137    
{
138        if(titles[i] == ce || arrows[i] ==
 ce)
139        
{
140            sm =
 i;
141        }

142    }

143
144    //当前菜单项是展示状态时

145    if(parseInt(submenus[sm].style.height) > parseInt(heights[sm])-2
146    
{
147
        hidemenu(sm);
148    }

149    else if(parseInt(submenus[sm].style.height) < 2)  //当是收缩状态
150    {
151        titles[sm].className = "title"
;
152
        
153        //当菜单只能展开一项(其余菜单项须全部收起)

154        if(contractall_default ==1)
155        
{
156
            slash_contractall();
157        }

158        //显示指定的菜单项
159        showmenu(sm);
160    }

161}

162
163//隐藏指定的菜单元素

164function hidemenu(sm) 
165
{
166    var nr = submenus[sm].getElementsByTagName("a").length*bypixels+
speed;
167    submenus[sm].style.height = (parseInt(submenus[sm].style.height)-nr)+"px"
;
168    var to = setTimeout("hidemenu("+sm+")"5
);
169

170    if(parseInt(submenus[sm].style.height) <=
 nr) 
171    
{
172
        clearTimeout(to);
173        submenus[sm].style.display = "none"
;
174        submenus[sm].style.height = "0px"
;
175        arrows[sm].src = imgpath+"/top_level_ico2.gif"
;
176        titles[sm].className = "titlehidden"
;
177    }

178}

179
180//显示指定的菜单元素

181function showmenu(sm) 
182
{
183    var nr = submenus[sm].getElementsByTagName("a").length*bypixels+
speed;
184    submenus[sm].style.display = ""
;
185    submenus[sm].style.height = (parseInt(submenus[sm].style.height)+nr)+"px"
;
186    var to = setTimeout("showmenu("+sm+")"30
);
187    if(parseInt(submenus[sm].style.height) > (parseInt(heights[sm])-
nr)) 
188    
{
189
        clearTimeout(to);
190        submenus[sm].style.height = heights[sm]+"px"
;
191        arrows[sm].src = imgpath+"/top_level_ico1.gif"
;
192    }

193}

194
195//保存菜单元素

196function store() 
197
{
198    var hidden = new
 Array();
199    for(var i in
 titles) 
200    
{
201        if(titles[i].className == "titlehidden"
)
202        
{
203
            hidden.push(i);
204        }

205    }

206    putcookie("menu", hidden.join(","), 5);
207}

208
209//获取指定样式的元素

210function getElementsByClassName(strClassName, strTagName, oElm){
211    var arrElements = (strTagName == "*" && document.all)?
 document.all : oElm.getElementsByTagName(strTagName);
212    var arrReturnElements = new
 Array();
213    strClassName = strClassName.replace(/\-/g, "\\-"
);
214    var oRegExp = new RegExp("(^|\\s)" + strClassName + "(\\s|$)"
);
215
    var oElement;
216    for(var i=0; i<arrElements.length; i++
)
217    
{
218        oElement =
 arrElements[i];      
219        if
(oRegExp.test(oElement.className))
220        
{
221
            arrReturnElements.push(oElement);
222        }
   
223    }

224    return (arrReturnElements)
225}

226
227
function putcookie(c_name,value,expiredays) 
228
{
229    var exdate=new
 Date();
230    exdate.setDate(exdate.getDate()+
expiredays);
231    document.cookie = c_name + "=" + escape(value) + ((expiredays==null? "" : ";expires="+
exdate);
232}

233
234
function getcookie(c_name) 
235
{
236    if(document.cookie.length > 0

237    
{
238        var c_start = document.cookie.indexOf(c_name + "="
);
239        if(c_start != -1
)
240        
{
241            c_start = c_start + c_name.length + 1
;
242            var c_end = document.cookie.indexOf(";"
,c_start);
243            if(c_end == -1
)
244            
{
245                c_end =
 document.cookie.length;
246            }

247            return unescape(document.cookie.substring(c_start, c_end));
248        }

249    }

250    return null;
251}

252
253window.onload =
 init;
254

255

 

    其余的大家可以详细看一下包中的相关内容即可, 这里就不再多说了:)

 
    好了,主要是东西就先交待到这里了。如果大家有什么问题或建议,欢迎与我交流,我的邮件是daizhj@discuz.com,
daizhj617595@126.com  
    

    下载地址:/Files/daizhj/navmenu.rar

    关键字: .net, 控件, navmenu, 导航, control, discuz, discuz!nt, discuznt, 代震军, daizhj
 
  

 


 

posted on 2007-12-04 12:29 代震军 阅读(5083) 评论(21) 编辑 收藏

FeedBack:
2007-12-04 12:32 | stone_zhu[未注册用户]
D一个,用过DISCUZNT的左栏:)
 回复 引用   
2007-12-04 12:53 | Jacky_xu      
不错。马上研究一下!!!
 回复 引用 查看   
2007-12-04 13:26 | llkj[未注册用户]
谢谢楼主分享!我们网站用的NT2.0。
楼主能不能讲讲,为什么这样设计?
另外,2.0什么时间开源?有没有明确的时间?

 回复 引用   
2007-12-04 13:42 | Enzo      
@llkj
官方有说要开源 但时间还不确定

 回复 引用 查看   
#5楼[楼主]
2007-12-04 14:01 | daizhj      
@llkj
@ Enzo
您好,我们产品组目前正在将BUG收集整理并进行修改。会在近一天两开始进行代码的检查和补充一些注释说明。相信开源的时间不会太久了:)

 回复 引用 查看   
2007-12-04 14:52 | discuz[未注册用户]
很乱,代码写的也看难
 回复 引用   
2007-12-04 15:14 | GoGoSonny      
浏览器兼容做了不?
有2.0的DNT的下载链接不?
不大想开百度搜了。。。

 回复 引用 查看   
#8楼[楼主]
2007-12-04 15:50 | daizhj      
@GoGoSonny
兼容FIREFOX

 回复 引用 查看   
#9楼[楼主]
2007-12-04 15:51 | daizhj      
@discuz
恶搞几时休呀:(

 回复 引用 查看   
#10楼[楼主]
2007-12-04 18:37 | daizhj      
@Jacky_xu
过奖了:)

 回复 引用 查看   
2007-12-04 21:21 | cw[未注册用户]
建议2.0哪个版本的后台管理不要用帧结构, 感觉哪样不好. 当列表很长时使用反而不方便. 其他都不错了.
 回复 引用   
2007-12-05 02:23 | reaper[未注册用户]
支持
 回复 引用   
#13楼[楼主]
2007-12-05 11:16 | daizhj      
@reaper
呵呵:)

 回复 引用 查看   
2007-12-05 13:23 | monster_DD[未注册用户]
为什么大部分变量名全部采用小写,你用记事本打开看恶心不,另外,团队没有规范么?光从命名就能看出代码不是一个人写的了
 回复 引用   
#15楼[楼主]
2007-12-05 16:13 | daizhj      
@monster_DD
当然有开发规范了,您可以找一下DISCUZ和DISCUZNT中的JS看一下,基本上都是小写,而函数命名也基本上都是首字母小写,没什么可大尺小怪的,的确这个代码后来被改动了一些,但基本上还是延缓已有风格。偶尔的别扭是改变不了整体规范的.

 回复 引用 查看   
2007-12-05 20:51 | monster_DD[未注册用户]
@daizhj
2.0的我还没看,随便从1.0的里面找几句,BasePage.cs里面的
templatelistboxoptions = CacheFactory.GetTemplateListBoxOptionsCache();

sseccode =Utils.InArray(pagename, config.Seccodestatus);
lastposttime= oluserinfo.Lastposttime;
lastpostpmtime = oluserinfo.Lastpostpmtime;
lastsearchtime = oluserinfo.Lastsearchtime;



 回复 引用   
#17楼[楼主]
2007-12-06 09:37 | daizhj      
@monster_DD
关于您所说的我可以解释一下,首先是JS的书写,基本上是与discuz Php 是一样的,也就是我上面跟您说的那种写法。
而C#代码中,类或方法基本上按单词首字母大写,而所用的变量基本上都是小写,与js方面类似。
而oluserinfo.Lastposttime这样的语句中Lastposttime,为什么不是LastPostTime,主要是因为前台模板语法的要求,因为Lastposttime这样的写法会在模板翻译生成时会比较方便。
当然,因为开发人员以前的编码习惯不同而造成的少量代码书写不规范也是在所难免。我们发现一处就会修改一处。但总体上还是参考已有的书写规范。
不知道我这样解释您是否完全明白。

如果有疑问请您跟贴。
同时感谢您对我们产品的关注:)

 回复 引用 查看   
2007-12-06 13:17 | monster_DD[未注册用户]
@daizhj
好的,感谢您的回复,一直在学习dnt,原谅我的挑刺,只是希望dnt产品越做越好:)

 回复 引用   
#19楼[楼主]
2007-12-06 13:45 | daizhj      
@monster_DD
客气了,其实只有像您这样的用户和开发者的关注和监督才会让产品质量有保障:)

 回复 引用 查看   
2007-12-09 11:32 | chy710      
@daizhj
给你留言了

 回复 引用 查看   
#21楼[楼主]
2007-12-10 13:15 | daizhj      
@chy710
我已将联系人的EMAIL地址给了您(您的GMAIL地址),以后您可直接与他联系即可.
同时感谢您对我们产品的支持和关注:)

 回复 引用 查看   
昵称:代震军
园龄:5年11个月
荣誉:推荐博客
粉丝:492
关注:3

<2007年12月>
2526272829301
2345678
9101112131415
16171819202122
23242526272829
303112345

搜索

 
 

常用链接

随笔分类(366)

随笔档案(283)

文章分类(8)

文章档案(31)

相册

JavaScript

LINQ

silverlight

UML,OO

WebBlogger

负载开源项目

  • Discuz!NT
  • LLServer
  • TokyoTyrantClient
  • WebCam

个人简历

漫画

其它

企业级架构

网站案例研究

积分与排名

  • 积分 - 1217876
  • 排名 - 26

最新评论

阅读排行榜

评论排行榜

推荐排行榜