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

效果图2:

首先将相应的C#代码放出来:
1Property ScriptPath#region Property ScriptPath 2 3 /**//// <summary> 4 /// Javascript脚本文件所在目录。 5 /// </summary> 6 [Description("Javascript脚本文件所在目录。"),DefaultValue("./")] 7 public string ScriptPath 8 { 9 get 10 { 11 object obj = ViewState["NavMenuScriptPath"]; 12 return obj == null ? "js/Navbar.js" :(string) obj; 13 } 14 set 15 { 16 ViewState["NavMenuScriptPath"] = value; 17 } 18 } 19 20 #endregion 21 22 23 Property ImageUrl#region Property ImageUrl 24 [Bindable(true), Category("Appearance"), DefaultValue("")] 25 public string ImageUrl 26 { 27 get 28 { 29 if (base.ViewState["NavMenuimageurl"] != null) 30 { 31 return (String)base.ViewState["NavMenuimageurl"]; 32 } 33 else 34 { 35 return "images/";//String.Empty; 36 } 37 } 38 set 39 { 40 base.ViewState["NavMenuimageurl"] = value; 41 } 42 } 43 44 #endregion 45 46 47 Property CssPath#region Property CssPath 48 49 /**//// <summary> 50 /// Css文件所在目录。 51 /// </summary> 52 [Description("Javascript脚本文件所在目录。"),DefaultValue("./")] 53 public string CssPath 54 { 55 get 56 { 57 object obj = ViewState["NavMenuCssPath"]; 58 return obj == null ? "styles/nav.css" :(string) obj; 59 } 60 set 61 { 62 ViewState["NavMenuCssPath"] = value; 63 } 64 } 65 66 #endregion 67 68 69 Property XmlFileFullPathName#region Property XmlFileFullPathName 70 71 /**//// <summary> 72 /// Xml文件所在目录。 73 /// </summary> 74 [Description("Xml文件所在目录。"),DefaultValue("./")] 75 public string XmlFileFullPathName 76 { 77 get 78 { 79 object obj = ViewState["NavMenuXmlFileFullPathName"]; 80 return obj == null ? "xml/navmenu.xml" :(string) obj; 81 } 82 set 83 { 84 ViewState["NavMenuXmlFileFullPathName"] = value; 85 } 86 } 87 88 #endregion 89 90 protected override void OnPreRender(EventArgs e)#region protected override void OnPreRender(EventArgs e) 91 /**//// <summary> 92 /// 重写<see cref="System.Web.UI.Control.OnPreRender"/>方法。 93 /// </summary> 94 /// <param name="e">包含事件数据的 <see cref="EventArgs"/> 对象。</param> 95 protected override void OnPreRender(EventArgs e) 96 { 97 StringBuilder sb = new StringBuilder(); 98 99 sb.Append("<script type="text/javascript" src="" + this.ScriptPath + ""></script>rn"); 100 sb.Append("<link rel="stylesheet" type="text/css" href="" + this.CssPath + "" />rn"); 101 sb.Append("<script type="text/javascript">var imgpath="" + this.ImageUrl + "";</script>rn"); 102 sb.Append("<script language="javascript" src="" + this.ScriptPath + ""></script>rn"); 103#if NET1 104 if (!Page.IsClientScriptBlockRegistered("NavMenu")) 105 { 106 Page.RegisterClientScriptBlock("NavMenu", sb.ToString()); 107 } 108#else 109 if (!Page.ClientScript.IsClientScriptBlockRegistered("NavMenu")) 110 { 111 Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "NavMenu", sb.ToString()); 112 } 113#endif 114 115 base.OnPreRender(e); 116 } 117 118 #endregion 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">rn"); 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 输出主菜单#region 输出主菜单 136 output.Write(" <table>rn"); 137 output.Write("<tr>rn"); 138 if(count==0) 139 { 140 output.Write("<td width="196px"><span class="title" id="top">"+ 141 dr["menutitle"]+"</span></td>rn"); 142 } 143 else 144 { 145 output.Write("<td width="196px"><span class="title">"+ 146 dr["menutitle"]+"</span></td>rn"); 147 } 148 output.Write("<td><img src=""+this.ImageUrl+"/top_level_ico1.gif" 149 class="arrow" /></td>rn"); 150 output.Write("</tr>rn"); 151 output.Write("</table>rn"); 152 #endregion 153 154 输出子菜单#region 输出子菜单 155 output.Write(" <div class="submenu">rn"); 156 output.Write("<table>rn"); 157 foreach(System.Data.DataRow drs in dsSrc.Tables[1].Select("menuparentid=""+ 158 dr["menuid"]+""")) 159 { 160 161 output.Write("<tr>rn"); 162 if(drs["imgurl"].ToString().Trim()!="") 163 { 164 output.Write(" <td class="lefttd" ><img src=""+ 165 drs["imgurl"].ToString().Trim()+"" 166 class="submenuimg" align="absmiddle"/></td>"); 167 } 168 else 169 { 170 output.Write(" <td class="lefttd" ></td>"); 171 } 172 if((drs["frameid"].ToString().Trim()=="top")||(drs["frameid"].ToString(). 173 Trim()=="")) 174 { 175 output.Write("<td><a href="javascript:void(0);" 176 onclick="javascript:top.location.href=""+ 177 drs["link"].ToString().Trim()+"";" 178 onfocus="this.blur();">"+ 179 drs["menutitle"].ToString().Trim()+"</a></td>rn"); 180 } 181 else 182 { 183 output.Write("<td><a href=""+drs["link"].ToString().Trim()+"" 184 target="+drs["frameid"].ToString().Trim()+" 185 onfocus="this.blur();">"+ 186 drs["menutitle"].ToString().Trim()+"</a></td>rn"); 187 } 188 output.Write("</tr>rn"); 189 } 190 output.Write("</table>rn"); 191 output.Write("</div>rn"); 192 #endregion 193 194 //打印分割符 195 output.Write("<div class="splitter"> </div>rn"); 196 count++; 197 } 198 199 output.Write("</div>rn"); 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 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
源代码网供稿. |