asp.net自带的菜单控件采用的table和javascript,导致生成的大量的html,同时在很多浏览器中都无法显示出子菜单,也只能在IE中能显示出来。
本文介绍的菜单控件采用的css 和ul list来显示菜单,生成的html小,无需javascript支持,对大部分的浏览器都支持,除ie6要单独修改css也可以使其支持。
通过本文可以了解asp.net 控件的开发,及Composite设计模式的实际运用。
采用Composite设计模式设计菜单类:
MenuCompositeitem类
{
[Serializable()]
public class MenuCompositeItem
{
private List < MenuCompositeItem > _children = new List < MenuCompositeItem > ();
private string _text;
private string _link;
private string _target;
/// <summary>
/// 菜单项
/// </summary>
/// <param name="text"> 菜单名 </param>
/// <param name="link"> 链接 </param>
public MenuCompositeItem( string text, string link)
{
this ._text = text;
this ._link = link;
}
/// <summary>
/// 菜单项
/// </summary>
/// <param name="text"> 菜单名 </param>
/// <param name="link"> 链接 </param>
/// <param name="target"> 跳转目标 </param>
public MenuCompositeItem( string text, string link, string target)
{
this ._text = text;
this ._link = link;
this ._target = target;
}
/// <summary>
/// 设置或获取菜单名
/// </summary>
public string Text
{
get { return _text; }
set { _text = value; }
}
/// <summary>
/// 设置或获取链接
/// </summary>
public string Link
{
get { return _link; }
set { _link = value; }
}
/// <summary>
/// 跳转目标
/// </summary>
public string Target
{
get { return _target; }
set { _target = value; }
}
/// <summary>
/// 设置或获取子菜单
/// </summary>
public List < MenuCompositeItem > Children
{
get { return _children; }
set { _children = value; }
}
}
MenuComposite类
{
[DefaultProperty( " Menu " )]
[ToolboxData( " <{0}:MenuComposite runat=server></{0}:MenuComposite> " )]
public class MenuComposite : WebControl
{
/// <summary>
/// 设置获取选择的菜单
/// </summary>
[Bindable( true )]
[DefaultValue( "" )]
[Localizable( true )]
public string SelectedMenuText
{
get
{
String s = (String)ViewState[ " SelectedMenuText " ];
return ((s == null ) ? String.Empty : s);
}
set
{
ViewState[ " SelectedMenuText " ] = value;
}
}
/// <summary>
/// 获取和设置菜单项从ViewState
/// </summary>
[Bindable( true )]
[DefaultValue( null )]
[Localizable( true )]
public MenuCompositeItem MenuItems
{
get
{
return ViewState[ " MenuItems " ] as MenuCompositeItem;
}
set
{
ViewState[ " MenuItems " ] = value;
}
}
/// <summary>
/// 呈现菜单结构
/// </summary>
/// <param name="output"> HTML输出流 </param>
protected override void RenderContents(HtmlTextWriter output)
{
MenuCompositeItem root = this .MenuItems;
output.Write( @" <div class=""navmenu""> " );
output.Write( @" <ul> " );
for ( int i = 0 ; i < root.Children.Count; i ++ )
{
RecursiveRender(output, root.Children[i]);
}
output.Write( @" </ul> " );
output.Write( @" </div> " );
}
/// <summary>
/// 递归输出菜单项
/// </summary>
/// <param name="output"> HTML输出流 </param>
/// <param name="item"> 菜单项. </param>
/// <param name="depth"> Indentation depth. </param>
private void RecursiveRender(HtmlTextWriter output, MenuCompositeItem item)
{
output.Write( " <li> " );
if ( string .IsNullOrEmpty(item.Target)) // 为空不设置跳转目标
{
output.Write( @" <a href="" " + item.Link + @" ""> " );
}
else
{
output.Write( @" <a href="" " + item.Link + @" "" target= "" " + item.Target + @" ""> " );
}
if (item.Text == SelectedMenuText) // 选中的菜单
{
output.Write( @" <span class=""selected""> " );
output.WriteLine(item.Text);
output.WriteLine( " </span> " );
}
else
{
output.Write(item.Text);
}
output.Write( " </a> " );
if (item.Children.Count > 0 )
{
output.WriteLine();
output.Write( " <ul> " );
for ( int i = 0 ; i < item.Children.Count; i ++ )
{
RecursiveRender(output, item.Children[i]);
}
output.Write( " </ul> " );
}
output.Write( " </li> " );
}
}
}
在页面中使用
添加对控件的引用后就可以直接在“工具箱”-》Controls组件中 看到MenuComposite组件
再就可以像其他asp.net 控件一样使用
使用:
MenuCompositeItem menu01 = new MenuCompositeItem( " menu01 " , ResolveUrl( " ~/Default.aspx " ));
MenuCompositeItem menu02 = new MenuCompositeItem( " menu02 " , ResolveUrl( " ~/Default.aspx " ));
MenuCompositeItem menu03 = new MenuCompositeItem( " menu03 " , ResolveUrl( " ~/Default.aspx " ));
MenuCompositeItem menu04 = new MenuCompositeItem( " menu04 " , ResolveUrl( " ~/Page04.aspx " ));
MenuCompositeItem menu05 = new MenuCompositeItem( " menu05 " , ResolveUrl( " ~/Default.aspx " ));
MenuCompositeItem menu01_01 = new MenuCompositeItem( " menu01-01 " , ResolveUrl( " ~/Default.aspx " ));
MenuCompositeItem menu01_02 = new MenuCompositeItem( " menu01-02 " , ResolveUrl( " ~/Page01-02.aspx " ));
MenuCompositeItem menu01_03 = new MenuCompositeItem( " menu01-03 " , ResolveUrl( " ~/Default.aspx " ));
MenuCompositeItem menu01_04 = new MenuCompositeItem( " menu01-04 " , ResolveUrl( " ~/Default.aspx " ));
menu01.Children.Add(menu01_01);
menu01.Children.Add(menu01_02);
menu01.Children.Add(menu01_03);
menu01.Children.Add(menu01_04);
MenuCompositeItem menu02_01 = new MenuCompositeItem( " menu02-01 " , ResolveUrl( " ~/Default.aspx " ));
MenuCompositeItem menu02_02 = new MenuCompositeItem( " menu02-02 " , ResolveUrl( " ~/Default.aspx " ), " menu02-02 " );
menu02.Children.Add(menu02_01);
menu02.Children.Add(menu02_02);
MenuCompositeItem menu04_01 = new MenuCompositeItem( " menu04-01 " , ResolveUrl( " ~/Default.aspx " ));
MenuCompositeItem menu04_02 = new MenuCompositeItem( " menu04-02 " , ResolveUrl( " ~/Page04-02.aspx " ), " _blank " );
menu04.Children.Add(menu04_01);
menu04.Children.Add(menu04_02);
root.Children.Add(menu01);
root.Children.Add(menu02);
root.Children.Add(menu03);
root.Children.Add(menu04);
root.Children.Add(menu05);
TheMenuComposite.MenuItems = root;
此时生成的编译运行后会生成一个没有样式Ul list ,效果如下:
因此要生成可显示和隐藏的菜单项,关键在css的设置上,开始时将二级子菜单设置为隐藏visibility: hidden;
同时定义li的hover事件,li:hover时:自菜单的 visibility要改为visible; 大致原理是这样,当然还有注意菜单项的位置
一级菜单float:left;使其能水平显示。
CSS定义如下:
{
margin : 0 ;
padding : 0 ;
}
.navmenu
{
border : #000 1px solid ;
height : 25px ;
}
.navmenu li
{
/* 水平菜单 */
float : left ;
list-style : none ;
position : relative ;
}
.navmenu a
{
display : block ;
font-size : 12px ;
height : 24px ;
width : 100px ;
line-height : 24px ;
background-color : #CDEB8B ;
color : #0000ff ;
text-decoration : none ;
text-align : center ;
border-left : #36393D 1px inset ;
border-right : #36393D 1px inset ;
border-bottom : #36393D 1px inset ;
}
/* 单独设置一级菜单样式 */
.navmenu > ul > li > a
{
font-size : 11px ;
font-weight : bold ;
}
.navmenu a:hover
{
background : #369 ;
color : #fff ;
}
/* 新增的二级菜单部分 */
.navmenu ul ul
{
visibility : hidden ; /* 开始时是隐藏的 */
position : absolute ;
left : 0px ;
top : 24px ;
}
.navmenu ul li:hover ul, .navmenu ul a:hover ul
{
visibility : visible ;
}
.navmenu ul ul li
{
clear : both ; /* 垂直显示 */
text-align : left ;
}
/* 选中菜单项 */
.navmenu .selected
{
padding-left : 15px ;
background-position-x : 0px ;
background-image : url(./res/selected.gif) ;
background-repeat : no-repeat ;
text-decoration : underline ;
}
定义CSS后的效果如下:
到此菜单控件已完成。已测试过可以在IE7,IE8,Chrome,Firefox中正常显示,在IE6显示可能会有问题,可以参考纯CSS多级菜单 进行修改,
本文的CSS显示部分参考了此文的介绍。
附上完整代码,如需要可自行下载修改:/Files/ruinet/WebMenu.zip