Лучший способ получить активную ссылку на страницу в 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;
}

etc.

меню 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 54

6 ответов:

лучше использовать 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, добавить <add namespace="yourNamespacehere.Helpers" /> внутри тега, пространства имен. Затем создайте свой проект и закройте и снова откройте окно вы добавляете это.

затем на основе текущего действия и контроллера помощник добавит или нет active класс при создании якоря.

расширяя пример Дарина, вот полный класс, который добавляет дополнительные необязательные параметры для 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());
        }
    }
}

и в веб-вид папок.config:

<system.web.webPages.razor>
  <host ... />
  <pages ... >
    <namespaces>
      ...

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

используйте этот InnerHtml, если вы хотите включить форматирование HTML в свой текст;

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

текст может быть " Жирныйнормальный";

обновлено для 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"); линия, чтобы указать на пользовательский класс, если вы хотите оставить загрузочный "активный" класс в покое. Я добавил один под названием "activemenu" на сайте проекта.css-файл и сделал какие-либо конкретные изменения стиля navbar, которые я хотел там.

строка в коде выше была просто изменена на это, чтобы все это работало:

li.AddCssClass("activemenu");

In Сайт.CSS я добавил простой класс для моей цели:

.activemenu {
    text-decoration: underline;
}

кроме того, вы можете изменить цвет фона и/или границы и т. д...

вот расширение класса Дарина для вставки 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>