在MVC 3 Razor中获得活动页面链接的更好的方法

当我想要一个特定的菜单链接在一个给定的页面处于活动状态时,我在Razor中使用了这种方法:

在主布局上我有这些检查:

var active = ViewBag.Active; const string ACTIVE_CLASS = "current"; if (active == "home") { ViewBag.ActiveHome = ACTIVE_CLASS; } if (active == "products") { ViewBag.ActiveProducts = ACTIVE_CLASS; } 

等等

主布局上的HTML菜单:

 <ul> <li class="@ViewBag.ActiveHome"><a href="/">Home</a></li> <li class="@ViewBag.ActiveProducts"><a href="@Url.Action("index", "products")">Products</a></li> </ul> 

指定在不同视图上使用哪个布局页面时:

 @{ ViewBag.Active = "home"; Layout = "~/Views/Shared/_Layout.cshtml"; } 

有没有比我目前正在使用的更好的方式来sepcify活动链接?

更好的方法是使用HTML助手:

 using System.Web.Mvc; using System.Web.Mvc.Html; public static class MenuExtensions { public static MvcHtmlString MenuItem( this HtmlHelper htmlHelper, string text, string action, string controller ) { var li = new TagBuilder("li"); var routeData = htmlHelper.ViewContext.RouteData; var currentAction = routeData.GetRequiredString("action"); var currentController = routeData.GetRequiredString("controller"); if (string.Equals(currentAction, action, StringComparison.OrdinalIgnoreCase) && string.Equals(currentController, controller, StringComparison.OrdinalIgnoreCase)) { li.AddCssClass("active"); } li.InnerHtml = htmlHelper.ActionLink(text, action, controller).ToHtmlString(); return MvcHtmlString.Create(li.ToString()); } } 

接着:

 <ul> @Html.MenuItem("Home", "Home", "Home") @Html.MenuItem("Products", "Index", "Products") </ul> 

为了完成上述工作,您需要您的视图来识别您的扩展名:在Views文件夹中的Web.config中,在名称空间标记内添加<add namespace="yourNamespacehere.Helpers" /> 。 然后build立你的项目,closures并重新打开你添加到这个视图。

那么基于当前动作和控制器,助手将在生成锚时添加或不添加active类。

在Darin的示例中展开,下面是完整的类,它为帮助器上的RouteValues和HtmlAttributes添加了额外的可选参数。 实际上,它的行为就像基本的ActionLink。

 using System; using System.Web.Mvc; using System.Web.Mvc.Html; namespace MYNAMESPACE.Helpers { public static class MenuExtensions { public static MvcHtmlString MenuItem(this HtmlHelper htmlHelper, string text, string action, string controller, object routeValues = null, object htmlAttributes = null) { var li = new TagBuilder("li"); var routeData = htmlHelper.ViewContext.RouteData; var currentAction = routeData.GetRequiredString("action"); var currentController = routeData.GetRequiredString("controller"); if (string.Equals(currentAction, action, StringComparison.OrdinalIgnoreCase) && string.Equals(currentController, controller, StringComparison.OrdinalIgnoreCase)) { li.AddCssClass("active"); } if (routeValues != null) { li.InnerHtml = (htmlAttributes != null) ? htmlHelper.ActionLink(text, action, controller, routeValues, htmlAttributes).ToHtmlString() : htmlHelper.ActionLink(text, action, controller, routeValues).ToHtmlString(); } else { li.InnerHtml = htmlHelper.ActionLink(text, action, controller).ToHtmlString(); } return MvcHtmlString.Create(li.ToString()); } } } 

在View文件夹的web.config中:

 <system.web.webPages.razor> <host ... /> <pages ... > <namespaces> ... ... <add namespace="MYNAMESPACE.Helpers" /> </namespaces> </pages> </system.web.webPages.razor> 

如果您想在文本中包含HTML格式,请使用此InnerHtml;

 li.InnerHtml = "<a href=\"" + new UrlHelper(htmlHelper.ViewContext.RequestContext).Action(action, controller).ToString() + "\">" + text + "</a>"; 

文本可以是“<b>粗体</ b>正常”;

RC2更新 – 对于那些想知道如何做到这一点在MVC6 / Asp.Net 5 – 类似,但微妙的不同。 现在没有MvcHtmlString ,并且RouteData完全不同。 此外,上下文对象现在应该是IHtmlContent而不是HtmlHelper

 using System; using Microsoft.AspNet.Mvc.Rendering; public static class MenuExtensions { public static IHtmlContent MenuItem( this IHtmlHelper htmlHelper, string text, string action, string controller ) { var li = new TagBuilder("li") { TagRenderMode = TagRenderMode.Normal }; var routeData = htmlHelper.ViewContext.RouteData; var currentAction = routeData.Values["action"].ToString(); var currentController = routeData.Values["controller"].ToString(); if (string.Equals(currentAction, action, StringComparison.OrdinalIgnoreCase) && string.Equals(currentController, controller, StringComparison.OrdinalIgnoreCase)) { li.AddCssClass("active"); } li.InnerHtml.AppendHtml(htmlHelper.ActionLink(text, action, controller)); return li; } } 

即使在新的Visual Studio 2013 MVC5 / Bootstrap项目中,此代码也非常适合我。 还要注意,你可以改变li.AddCssClass(“active”); 如果您想单独保留Bootstrap“active”类,则指向一个自定义类。 我在项目的Site.css文件中添加了一个名为“activemenu”的文件,并做了我想要的任何特定的导航栏样式更改。

上面的代码中的行刚刚更改为此以使其全部工作:

 li.AddCssClass("activemenu"); 

在Site.css中,我为我的目的添加了一个简单的类:

 .activemenu { text-decoration: underline; } 

或者,您可以更改背景颜色和/或边框等。

这里是Darin的类在链接文本中插入html而不是简单文本的延伸

 using System; using System.Web.Mvc; using System.Web.Mvc.Html; namespace YourNameSpaceHere { public static class MenuExtensions { public static MvcHtmlString MenuItem( this HtmlHelper htmlHelper, string html, string action, string controller ) { var li = new TagBuilder("li"); var routeData = htmlHelper.ViewContext.RouteData; var currentAction = routeData.GetRequiredString("action"); var currentController = routeData.GetRequiredString("controller"); if (string.Equals(currentAction, action, StringComparison.OrdinalIgnoreCase) && string.Equals(currentController, controller, StringComparison.OrdinalIgnoreCase)) { li.AddCssClass("active"); } //generate a unique id for the holder and convert it to string string holder = Guid.NewGuid().ToString(); string anchor = htmlHelper.ActionLink(holder, action, controller).ToHtmlString(); //replace the holder string with the html li.InnerHtml = anchor.Replace(holder, html); return MvcHtmlString.Create(li.ToString()); } } } 

并像这样使用它:

 <ul> @Html.MenuItem("<span class'ClassName'>Home</span>", "Home", "Home") </ul>