利用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>
最终呈现的效果如下所示:
菜单对应的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>