Discuz!NT控件剖析 之 左侧导航控件 [原创: 附源码]
其实这个控件的核心基本都在JS上,而相关的数据绑定和显示却非常简单。而需要说明的是在Discuz!NT的1.0
和2.0正式版,这个控件做过一些调整,当然改动也基本上是在JS上,今天给大家的源码是1.0正式版的代码,虽然
有些“旧”,但程序本身的思想没变,大家只要明白了这里的源码,有了这碗酒垫底,相信再看即将开源的2.0代码,
就会一目了然了。
好了,废话到此,马上开始今天的话题!
先请大家看一下这个控件运行时的效果图:
效果图1:
效果图2:

首先将相应的C#代码放出来:
Property ScriptPath21

22

23
Property ImageUrl45

46

47
Property CssPath67

68

69
Property XmlFileFullPathName89

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\"> </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,代码如下(详情见注释):
2
var remember = false; //记录当前菜单状态,当下次访问时使用3
var contractall_default= 1; //系统菜单项状态 1:只显示第一项 2:展开所有项 3:收缩所有的菜单项4

5
var menu, titles, submenus, arrows, bypixels; //定义指定的菜单数组变量6
var heights = new Array();7
var speed=10; //加载菜单项的速度 8

9
var n = navigator.userAgent;10

11
if(/Opera/.test(n)) 12
{13
bypixels = 2;14
}15
else if(/Firefox/.test(n)) 16
{17
bypixels = 3;18
}19
else if(/MSIE/.test(n)) 20
{21
bypixels = 2;22
}23

24

25
//展开所有菜单项26
function 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
//收缩所有菜单项42
function 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
//初始化函数59
function 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
//存储菜单项状态110
function 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
//定向到指定的菜单项进行相应操作124
function 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
//隐藏指定的菜单元素164
function 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
//显示指定的菜单元素181
function 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
//保存菜单元素196
function 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
//获取指定样式的元素210
function 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

253
window.onload = init;254

255

其余的大家可以详细看一下包中的相关内容即可, 这里就不再多说了:)
好了,主要是东西就先交待到这里了。如果大家有什么问题或建议,欢迎与我交流,我的邮件是daizhj@discuz.com,
daizhj617595@126.com
下载地址:/Files/daizhj/navmenu.rar
关键字: .net, 控件, navmenu, 导航, control, discuz, discuz!nt, discuznt, 代震军, daizhj


浙公网安备 33010602011771号