利用ASP.NET SiteMap生成与Bootstrap"兼容"菜单

Bootstrap是Twitter推出的一个开源的用于前端开发的工具包。它由Twitter的设计师Mark Otto和Jacob Thornton合作开发,是一个CSS/HTML框架。本文提供了一个解决方案利用ASP.NET SiteMap生成与Bootstrap“兼容”的菜单。具体的原理很简单,就是利用SiteMap读取预先定义的网站结构,按照Bootstrap的标准生成相应的HTML。[源代码从这里下载]

我们将基于菜单的呈现定义在HtmlHelper的扩展方法中。如下面的代码片断,扩展方法RenderBootstrapMenu具有一个缺省的参数siteMapProviderName ,表示读取SiteMap结构采用的SiteMapProvider的配置名称。在该方法中,我们通过指定的SiteMapProvider(如果没有指定,则采用默认配置的SiteMapProvider)得到代表整个SiteMap根节点的SiteMapNode对象,并将其子节点(以及子节点的子节点,…)转换成相应的HTML。

   1: public static class BootstrapMenuExtensions
   2: {        
   3:     public static MvcHtmlString RenderBootstrapMenu(this HtmlHelper helper, string siteMapProviderName = "")
   4:     {
   5:         SiteMapProvider siteMapProvider = !string.IsNullOrEmpty(siteMapProviderName) ?
   6:             SiteMap.Providers[siteMapProviderName] :
   7:             SiteMap.Provider ?? SiteMap.Providers.Cast<SiteMapProvider>().First();
   8:         return new MvcHtmlString( RenderMenu(siteMapProvider.RootNode.ChildNodes));
   9:     }
  10:  
  11:     private static string RenderMenu(SiteMapNodeCollection siteMapNodes)
  12:     {
  13:         TagBuilder ul = new TagBuilder("ul");
  14:         ul.AddCssClass("nav");
  15:         ul.AddCssClass("nav-pills");
  16:  
  17:         foreach (SiteMapNode node in siteMapNodes)
  18:         {
  19:             ul.InnerHtml += GetMenuItemHtml(node);
  20:         }
  21:         return ul.ToString();
  22:     }
  23:  
  24:     private static string GetMenuItemHtml(SiteMapNode siteMapNode)
  25:     {
  26:         TagBuilder li = new TagBuilder("li");
  27:         li.AddCssClass("dropdown");
  28:  
  29:         TagBuilder link = new TagBuilder("a");
  30:         link.Attributes.Add("href", siteMapNode.Url);
  31:         link.Attributes.Add("title", siteMapNode.Description);
  32:         link.SetInnerText(siteMapNode.Title);
  33:  
  34:         if (!siteMapNode.HasChildNodes)
  35:         {
  36:             li.InnerHtml += link.ToString();
  37:             return li.ToString();
  38:         }
  39:  
  40:         link.AddCssClass("dropdown-toggle");
  41:         link.Attributes.Add("data-toggle", "dropdown");
  42:         TagBuilder caret = new TagBuilder("b");
  43:         caret.AddCssClass("caret");
  44:         link.InnerHtml += caret.ToString();
  45:  
  46:         TagBuilder ul = new TagBuilder("ul");
  47:         ul.AddCssClass("dropdown-menu");
  48:         foreach (SiteMapNode node in siteMapNode.ChildNodes)
  49:         {
  50:             ul.InnerHtml += GetSubItemHtml(node);
  51:         }
  52:         li.InnerHtml += link.ToString();
  53:         li.InnerHtml += ul.ToString();
  54:         return li.ToString();
  55:     }
  56:  
  57:     private static string GetSubItemHtml(SiteMapNode siteMapNode)
  58:     {
  59:         TagBuilder li = new TagBuilder("li");
  60:  
  61:         TagBuilder link = new TagBuilder("a");
  62:         link.Attributes.Add("href", siteMapNode.Url);
  63:         link.Attributes.Add("title", siteMapNode.Description);
  64:         link.SetInnerText(siteMapNode.Title);
  65:         li.InnerHtml += link.ToString();
  66:  
  67:         if (siteMapNode.HasChildNodes)
  68:         {
  69:             link.AddCssClass("dropdown-toggle");
  70:             link.Attributes.Add("data-toggle", "dropdown");
  71:  
  72:             li.AddCssClass("dropdown-submenu");
  73:             TagBuilder ul = new TagBuilder("ul");
  74:             ul.AddCssClass("dropdown-menu");
  75:             foreach (SiteMapNode node in siteMapNode.ChildNodes)
  76:             {
  77:                 ul.InnerHtml += GetSubItemHtml(node);
  78:             }
  79:             li.InnerHtml += ul.ToString();
  80:         }
  81:         return li.ToString();
  82:     }
  83: }

假设我们采用XmlSiteMapProvider,SiteMap结构通过如下的XML来定义,整个结构具有三个层次。

   1: <?xml version="1.0" encoding="utf-8" ?>
   2: <siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >
   3:   <siteMapNode url="Root" title="Root"  description="">
   4:     <siteMapNode url="A1" title="A1"  description="1st Level 1" />
   5:     <siteMapNode url="A2" title="A2"  description="1st Level 2" />
   6:     <siteMapNode url="A3" title="A3"  description="1st Level 3">
   7:       <siteMapNode url="B1" title="B1"  description="2nd Level 1" />
   8:       <siteMapNode url="B2" title="B2"  description="2nd Level 2" />
   9:       <siteMapNode url="B3" title="B3"  description="2nd Level 3">
  10:         <siteMapNode url="C1" title="C1"  description="3rd Level 1" />
  11:         <siteMapNode url="C2" title="C2"  description="3rd Level 2" />
  12:         <siteMapNode url="C3" title="C3"  description="3rd Level 3" />
  13:       </siteMapNode>
  14:     </siteMapNode>
  15:   </siteMapNode>
  16: </siteMap>

在如下一个View中,我们调用扩展方法RenderBootstrapMenu将由上面这个XML定义的菜单节点呈现出来。

   1: <!DOCTYPE html>
   2: <html>
   3: <head>
   4:     <title>Bootstrap Menu</title>
   5:     <link href="bootstrap/css/bootstrap.min.css" rel="stylesheet" />    
   6: </head>
   7: <body>
   8:     <script type="text/javascript" src="http://code.jquery.com/jquery-latest.js"></script>
   9:     <script type="text/javascript" src="bootstrap/js/bootstrap.min.js"></script>
  10:     <div>
  11:         @Html.RenderBootstrapMenu()
  12:     </div>
  13: </body>
  14: </html>

最终呈现的效果如下所示:

image

菜单对应的HTML为:

   1: <ul class="nav-pills nav">
   2:     <li class="dropdown"><a href="/A1" title="1st Level 1">A1</a></li>
   3:     <li class="dropdown"><a href="/A2" title="1st Level 2">A2</a></li>
   4:     <li class="dropdown"><a class="dropdown-toggle" data-toggle="dropdown" href="/A3" title="1st Level 3">A3<b class="caret"></b></a>
   5:         <ul class="dropdown-menu">
   6:             <li><a href="/B1" title="2nd Level 1">B1</a></li>
   7:             <li><a href="/B2" title="2nd Level 2">B2</a></li>
   8:             <li class="dropdown-submenu"><a href="/B3" title="2nd Level 3">B3</a>
   9:                   <ul class="dropdown-menu">
  10:                        <li><a href="/C1" title="3rd Level 1">C1</a></li>
  11:                        <li><a href="/C2" title="3rd Level 2">C2</a></li>
  12:                        <li><a href="/C3" title="3rd Level 3">C3</a></li>
  13:                   </ul>
  14:             </li>
  15:         </ul>
  16:     </li>
  17: </ul>
posted @ 2012-10-16 17:26  Artech  阅读(8886)  评论(23编辑  收藏  举报