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

时间:2011-06-12 16:16:02

标签: c# asp.net-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";
}

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

6 个答案:

答案 0 :(得分:126)

更好的方法是使用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" />。然后构建项目并关闭并重新打开要添加到其中的视图。

然后基于当前操作和控制器,帮助器在生成锚点时将添加或不添加active类。

答案 1 :(得分:6)

扩展Darin的例子,这里是完整的类,它为helper上的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>

答案 2 :(得分:2)

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

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

文字可以是“&lt; b&gt; Bold&lt; / b&gt;正常”;

答案 3 :(得分:2)

为RC2更新 - 对于那些想知道如何在MVC6 / Asp.Net 5中执行此操作的人 - 类似但略有不同。现在没有MvcHtmlStringRouteData完全不同。此外,上下文对象现在应该是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;


    }
}

答案 4 :(得分:0)

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

上面代码中的行只是更改为此以使其全部正常工作:

li.AddCssClass("activemenu");

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

.activemenu {
    text-decoration: underline;
}

或者你可以改变背景颜色和/或边框等......

答案 5 :(得分:0)

这是对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>