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