Как добавить «активный» класс в Html.ActionLink в ASP.NET MVC


128

Я пытаюсь добавить «активный» класс к моей панели навигации начальной загрузки в MVC, но следующее не показывает активный класс, когда написано так:

<ul class="nav navbar-nav">
  <li>@Html.ActionLink("Home", "Index", "Home", null, new {@class="active"})</li>
  <li>@Html.ActionLink("About", "About", "Home")</li>
  <li>@Html.ActionLink("Contact", "Contact", "Home")</li>
</ul>

Это разрешает то, что выглядит как правильно отформатированный класс, но не работает:

<a class="active" href="/">Home</a>

В документации Bootstrap говорится, что теги «a» не должны использоваться на панели навигации, но я считаю, что приведенное выше является правильным способом добавления класса в Html.ActionLink. Есть ли другой (аккуратный) способ сделать это?


3
код, который разрешает, имеет в нем class = active. Разве вы не этого хотите в своем вопросе? Как у вас есть ваш код, так и я добавляю классы
Мэтт Бодили

ты не слишком понятен !!! Я не совсем понимаю, в чем проблема с добавлением его в навигацию, хотя у меня такое ощущение, что все должно быть в порядке
JC Lizard

1
В чем проблема с исправленным кодом? Чего ты ждешь? Не могли бы вы быть более конкретными, чем «похоже, не работает»? Ваш вопрос недостаточно ясен, чтобы помочь вам прямо сейчас.
dom

Под редакцией! извините, я имел в виду, что "активный" класс вообще не отображается
Гиллеспи

2
Просто взглянул на документацию Bootstrap, и я думаю, вам нужно добавить activeкласс к liэлементу, а не класс a. См. Первый пример здесь: getbootstrap.com/components/#navbar
dom

Ответы:


300

В Bootstrap activeкласс нужно применять к <li>элементу, а не к классу <a>. См. Первый пример здесь: http://getbootstrap.com/components/#navbar

То, как вы обрабатываете свой стиль пользовательского интерфейса в зависимости от того, что активно, а что нет, не имеет ничего общего с ActionLinkпомощником ASP.NET MVC . Это правильное решение, чтобы проследить за тем, как была построена платформа Bootstrap.

<ul class="nav navbar-nav">
    <li class="active">@Html.ActionLink("Home", "Index", "Home")</li>
    <li>@Html.ActionLink("About", "About", "Home")</li>
    <li>@Html.ActionLink("Contact", "Contact", "Home")</li>
</ul>

Редактировать:

Поскольку вы, скорее всего, будете повторно использовать свое меню на нескольких страницах, было бы разумно иметь способ автоматически применять этот выбранный класс на основе текущей страницы, а не копировать меню несколько раз и делать это вручную.

Самый простой способ это просто использовать значение , содержащимися в ViewContext.RouteData, а именно Actionи Controllerценности. Мы могли бы использовать то, что у вас есть сейчас, примерно так:

<ul class="nav navbar-nav">
    <li class="@(ViewContext.RouteData.Values["Action"].ToString() == "Index" ? "active" : "")">@Html.ActionLink("Home", "Index", "Home")</li>
    <li class="@(ViewContext.RouteData.Values["Action"].ToString() == "About" ? "active" : "")">@Html.ActionLink("About", "About", "Home")</li>
    <li class="@(ViewContext.RouteData.Values["Action"].ToString() == "Contact" ? "active" : "")">@Html.ActionLink("Contact", "Contact", "Home")</li>
</ul>

Это не очень красиво в коде, но он выполнит свою работу и позволит вам извлечь ваше меню в частичное представление, если хотите. Есть способы сделать это более чистым способом, но, поскольку вы только начинаете, я оставлю все как есть. Удачи в изучении ASP.NET MVC!


Позднее редактирование:

Этот вопрос, похоже, набирает обороты, поэтому я решил использовать более элегантное решение с использованием HtmlHelperрасширения.

Изменить 24.03.2015: пришлось переписать этот метод, чтобы разрешить множественные действия и контроллеры, запускающие выбранное поведение, а также обработку, когда метод вызывается из частичного представления дочернего действия, думал, что поделюсь обновлением!

public static string IsSelected(this HtmlHelper html, string controllers = "", string actions = "", string cssClass = "selected")
{
    ViewContext viewContext = html.ViewContext;
    bool isChildAction = viewContext.Controller.ControllerContext.IsChildAction;

    if (isChildAction)
        viewContext = html.ViewContext.ParentActionViewContext;

    RouteValueDictionary routeValues = viewContext.RouteData.Values;
    string currentAction = routeValues["action"].ToString();
    string currentController = routeValues["controller"].ToString();

    if (String.IsNullOrEmpty(actions))
        actions = currentAction;

    if (String.IsNullOrEmpty(controllers))
        controllers = currentController;

    string[] acceptedActions = actions.Trim().Split(',').Distinct().ToArray();
    string[] acceptedControllers = controllers.Trim().Split(',').Distinct().ToArray();

    return acceptedActions.Contains(currentAction) && acceptedControllers.Contains(currentController) ?
        cssClass : String.Empty;
}

Работает с .NET Core:

public static string IsSelected(this IHtmlHelper htmlHelper, string controllers, string actions, string cssClass = "selected")
{
    string currentAction = htmlHelper.ViewContext.RouteData.Values["action"] as string;
    string currentController = htmlHelper.ViewContext.RouteData.Values["controller"] as string;

    IEnumerable<string> acceptedActions = (actions ?? currentAction).Split(',');
    IEnumerable<string> acceptedControllers = (controllers ?? currentController).Split(',');

    return acceptedActions.Contains(currentAction) && acceptedControllers.Contains(currentController) ?
        cssClass : String.Empty;
}

Пример использования:

<ul>
    <li class="@Html.IsSelected(actions: "Home", controllers: "Default")">
        <a href="@Url.Action("Home", "Default")">Home</a>
    </li>
    <li class="@Html.IsSelected(actions: "List,Detail", controllers: "Default")">
        <a href="@Url.Action("List", "Default")">List</a>
    </li>
</ul>

Спасибо, как я уже упоминал, изначально у меня это было именно так, но я надеялся, что в моем коде будет один метод изменения «активного» класса между выбранными объектами.
Гиллеспи

2
@ Гиллеспи, не беспокойся! Я отредактировал свой ответ, чтобы добавить некоторую информацию, которая может помочь вам немного больше.
dom

5
Что касается первого редактирования, оно действительно работало только для страницы указателя. Похоже, причина в том, что когда он производил сравнение, оно не удалось, поскольку ViewContext.RouteData.Values ​​["Action"] не возвращает объект типа String (до сих пор не знаю, как это работало для первой страницы ....) , Когда я изменил все ViewContext.RouteData.Values ​​["Action"] на ViewContext.RouteData.Values ​​["Action"]. ToString (), это сработало для всех страниц. Вы можете добавить это в свое решение на случай, если у кого-то возникнет такая же проблема.
user3281466

2
@LonelyPixel, может быть, вам подходит этот ответ ?
dom

1
Для пользователей VB.NET: <li class = "@ (If (ViewContext.RouteData.Values ​​(" Action "). ToString () =" Index "," active "," "))"> @ Html.ActionLink (" Home »,« Index »,« Home ») </li>
Андреа Антонанджели

28

Расширение:

public static MvcHtmlString LiActionLink(this HtmlHelper html, string text, string action, string controller)
{
    var context = html.ViewContext;
    if (context.Controller.ControllerContext.IsChildAction)
        context = html.ViewContext.ParentActionViewContext;
    var routeValues = context.RouteData.Values;
    var currentAction = routeValues["action"].ToString();
    var currentController = routeValues["controller"].ToString();

    var str = String.Format("<li role=\"presentation\"{0}>{1}</li>",
        currentAction.Equals(action, StringComparison.InvariantCulture) &&
        currentController.Equals(controller, StringComparison.InvariantCulture) ?
        " class=\"active\"" :
        String.Empty, html.ActionLink(text, action, controller).ToHtmlString()
    );
    return new MvcHtmlString(str);
}

Использование:

<ul class="nav navbar-nav">
    @Html.LiActionLink("About", "About", "Home")
    @Html.LiActionLink("Contact", "Contact", "Home")
</ul>

1
Это очень эффективное расширение. Прекрасно работает и довольно элегантно. Снимаю перед вами шляпу, проф! Моя единственная претензия связана с тем role="presentation", что совсем не подходит для основного навигационного меню ( john.foliot.ca/aria-hidden/#pr ). Неупорядоченный список является подходящим контейнером для связанного набора ссылок, поскольку он логически группирует их вместе.
Рене Кабис

@ René Kåbis, это для начальной загрузки getbootstrap.com/components/#nav-tabs
Prof

1
Это не работает, когда пользователь вручную вводит URL-адрес строчными или прописными буквами, например. " domain.com/Login " и " domain.com/LOGIN ". Для решения var str = String.Format("<li role=\"presentation\"{0}>{1}</li>", currentAction.toLower().Equals(action.toLower(), StringComparison.InvariantCulture) && currentController.toLower().Equals(controller.toLower(), StringComparison.InvariantCulture) ? " class=\"active\"" : String.Empty, html.ActionLink(text, action, controller).ToHtmlString() );
sky91

20

Мне удалось это сделать, добавив параметр view bag в asp.net mvc. Вот что я наделал

Добавлен ViewBag.Current = "Scheduler";параметр Like на каждой странице

На странице макета

<ul class="nav navbar-nav">
     <li class="@(ViewBag.Current == "Scheduler" ? "active" : "") "><a href="@Url.Action("Index","Scheduler")" target="_self">Scheduler</a></li>
 </ul>

Это решило мою проблему.


Простое и легкое решение.
Джап Софи

13

Может быть немного поздно. Но надеюсь, что это поможет.

public static class Utilities
{
    public static string IsActive(this HtmlHelper html, 
                                  string control,
                                  string action)
    {
        var routeData = html.ViewContext.RouteData;

        var routeAction = (string)routeData.Values["action"];
        var routeControl = (string)routeData.Values["controller"];

        // both must match
        var returnActive = control == routeControl &&
                           action == routeAction;

        return returnActive ? "active" : "";
    }
}

И использование следующим образом:

<div class="navbar-collapse collapse">
    <ul class="nav navbar-nav">
        <li class='@Html.IsActive("Home", "Index")'>
            @Html.ActionLink("Home", "Index", "Home")
        </li>
        <li class='@Html.IsActive("Home", "About")'>
            @Html.ActionLink("About", "About", "Home")
        </li>
        <li class='@Html.IsActive("Home", "Contact")'>
            @Html.ActionLink("Contact", "Contact", "Home")
        </li>
    </ul>
</div>

Получил ссылку с http://www.codingeverything.com/2014/05/mvcbootstrapactivenavbar.html


1
Очень простое и элегантное решение. Я сделал некоторые улучшения здесь gist.github.com/jean-rakotozafy/…, чтобы выделить меню для всех действий контроллера.
Зан РАКОТО

5

Я знаю, что это старый вопрос, но я просто хочу добавить сюда свой голос. Я считаю, что это хорошая идея - оставить информацию о том, активна ли ссылка, контроллеру представления.

Я бы просто установил уникальное значение для каждого представления в действии контроллера. Например, если бы я хотел сделать ссылку на домашнюю страницу активной, я бы сделал что-то вроде этого:

public ActionResult Index()
{            
    ViewBag.Title = "Home";
    ViewBag.Home = "class = active";
    return View();
}

Тогда, на мой взгляд, я напишу примерно так:

<li @ViewBag.Home>@Html.ActionLink("Home", "Index", "Home", null, new { title = "Go home" })</li>

Когда вы переходите на другую страницу, скажем «Программы», ViewBag.Home не существует (вместо этого существует ViewBag.Programs); следовательно, ничего не отображается, даже class = "". Я думаю, что это чище и по ремонтопригодности, и по чистоте. Я всегда стараюсь исключить логику из поля зрения насколько это возможно.


4

Учитывая то, что опубликовал Дамит, мне нравится думать, что вы можете просто квалифицироваться как активный с помощью Viewbag.Title (лучше всего заполнить его на своих страницах с контентом, чтобы ваша _Layout.cshtmlстраница содержала ваши панели ссылок). Также обратите внимание, что если вы используете элементы подменю, он также отлично работает:

<li class="has-sub @(ViewBag.Title == "Dashboard 1" || ViewBag.Title == "Dashboard 2" ? "active" : "" )">
    <a href="javascript:;">
        <b class="caret"></b>
        <i class="fa fa-th-large"></i>
        <span>Dashboard</span>
    </a>
    <ul class="sub-menu">
        <li class="@(ViewBag.Title == "Dashboard 1" ? "active" : "")"><a href="index.html">Dashboard v1</a></li>
        <li class="@(ViewBag.Title == "Dashboard 2" ? "active" : "")"><a href="index_v2.html">Dashboard v2</a></li>
    </ul>
</li>

Чисто и эффективно!
mggluscevic

3

Я изменил ответ dom «не очень» и сделал его более уродливым. Иногда два контроллера имеют конфликтующие имена действий (например, индекс), поэтому я делаю следующее:

<ul class="nav navbar-nav">
  <li class="@(ViewContext.RouteData.Values["Controller"].ToString() + ViewContext.RouteData.Values["Action"].ToString() == "HomeIndex" ? "active" : "")">@Html.ActionLink("Home", "Index", "Home")</li>
  <li class="@(ViewContext.RouteData.Values["Controller"].ToString() + ViewContext.RouteData.Values["Action"].ToString() == "AboutIndex" ? "active" : "")">@Html.ActionLink("About", "Index", "About")</li>
  <li class="@(ViewContext.RouteData.Values["Controller"].ToString() + ViewContext.RouteData.Values["Action"].ToString() == "ContactHome" ? "active" : "")">@Html.ActionLink("Contact", "Contact", "Home")</li>
</ul>

3

Вы можете попробовать это: в моем случае я загружаю меню из базы данных на основе доступа на основе ролей, напишите код в каждом своем представлении, какое меню вы хотите активировать на основе вашего представления.

<script type="text/javascript">
        $(document).ready(function () {         
            $('li.active active-menu').removeClass('active active-menu');
            $('a[href="https://stackoverflow.com/MgtCustomer/Index"]').closest('li').addClass('active active-menu');
        });
</script>

3

Это простое решение для Asp.net MCV 5.

  1. Например, создайте статический класс Utilitarios.cs.

  2. Внутри класса создайте статический метод:

    public static string IsLinkActive(this UrlHelper url, string action, string controller)
    {
        if (url.RequestContext.RouteData.Values["controller"].ToString() == controller &&
            url.RequestContext.RouteData.Values["action"].ToString() == action)
        {
            return "active";
        }
    
        return "";
    }
  3. позвони так

    <ul class="sidebar-menu" data-widget="tree">
        <li class="header">HEADER</li>
        <li class="@Url.IsLinkActive("Index", "Home")">
            <a href="@Url.Action("Index", "Home")"><i class="fa fa-link"></i> <span>Home</span></a>
        </li>
        <li class="@Url.IsLinkActive("About", "Home")">
            <a href="@Url.Action("About", "Home")"><i class="fa fa-link"></i><span>About</span></a>
        </li>
    </ul>

3

ASP.NET Core и Bootstrap 4

Самый последний ответ

Я переработал аккуратное решение @crush для обновленного, совместимого с ASP.NET Core и Bootstrap 4 способа решения этой проблемы на основе IHtmlHelperметода расширения:

public static class LinkExtensions
{
    public static IHtmlContent ActiveActionLink(this IHtmlHelper html, string linkText, string actionName, string controllerName, object routeValues, object htmlAttributes)
    {
        return ActiveActionLink(html, linkText, actionName, controllerName, new RouteValueDictionary(routeValues), HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
    }

    public static IHtmlContent ActiveActionLink(this IHtmlHelper html, string linkText, string actionName, string controllerName, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes)
    {
        var routeData = html.ViewContext.RouteData;
        var routeAction = (string)routeData.Values["action"];
        var routeController = (string)routeData.Values["controller"];

        var active = controllerName.Equals(routeController) && actionName.Equals(routeAction);

        using (var writer = new StringWriter())
        {
            writer.WriteLine($"<li class='nav-item {(active ? "active" : "")}'>");
            html.ActionLink(linkText, actionName, controllerName, routeValues, htmlAttributes).WriteTo(writer, HtmlEncoder.Default);
            writer.WriteLine("</li>");
            return new HtmlString(writer.ToString());
        }
    }
}

использование

<nav class="navbar">
    <div class="collapse navbar-collapse">
        <ul class="navbar-nav">
            @Html.ActiveActionLink("Home", "Index", "Home", null, new { @class = "nav-link" })
            @Html.ActiveActionLink("About", "About", "Home", null, new { @class = "nav-link" })
            @Html.ActiveActionLink("Contact", "Contact", "TimeTracking", null, new { @class = "nav-link" })
        </ul>
    </div>
</nav>

1
Очень хорошее решение. В вашем примере, как я могу установить «Контакт» как активный по умолчанию?
Md. Suman Kabir,

1
Спасибо. Хорошо то, что вам не нужно устанавливать активный элемент. Как только будет посещена страница «Контакты», ActiveActionLink()будет применен активный класс к <li>:-)
WoIIe

где ты проверяешь район?
Мохаммад

@ Мохаммад Я не понимаю. Не могли бы вы уточнить свой вопрос?
WoIIe

в классе LinkExtensions вы не получили область из routeData!
Мохаммад

3

Easy ASP.NET Core 3.0 и TagHelpers

[HtmlTargetElement("li", Attributes = "active-when")]
public class LiTagHelper : TagHelper
{
    public string ActiveWhen { get; set; }

    [ViewContext]
    [HtmlAttributeNotBound]
    public ViewContext ViewContextData { get; set; }

    public override void Process(TagHelperContext context, TagHelperOutput output)
    {
        if (ActiveWhen == null)
            return;

        var targetController = ActiveWhen.Split("/")[1];
        var targetAction = ActiveWhen.Split("/")[2];

        var currentController = ViewContextData.RouteData.Values["controller"].ToString();
        var currentAction = ViewContextData.RouteData.Values["action"].ToString();

        if (currentController.Equals(targetController) && currentAction.Equals(targetAction))
        {
            if (output.Attributes.ContainsName("class"))
            {
                output.Attributes.SetAttribute("class", $"{output.Attributes["class"].Value} active");
            }
            else
            {
                output.Attributes.SetAttribute("class", "active");
            }
        }
    }
}

Включите в свой _ViewImports.cs:

@addTagHelper *, YourAssemblyName

Использование:

 <li active-when="/Home/Index">

2

Добавьте '.ToString', чтобы улучшить сравнение в ASP.NET MVC

<ul class="nav navbar-nav">
<li class="@(ViewContext.RouteData.Values["Action"].ToString() == "Index" ? "active" : "")">@Html.ActionLink("Home", "Index", "Home")</li>
<li class="@(ViewContext.RouteData.Values["Action"].ToString() == "About" ? "active" : "")">@Html.ActionLink("About", "About", "Home")</li>
<li class="@(ViewContext.RouteData.Values["Action"].ToString() == "Contact" ? "active" : "")">@Html.ActionLink("Contact", "Contact", "Home")</li>

-


Это не сработает, если в двух разных контроллерах используются одинаковые имена действий. Проверьте это с помощью контроллеров Home и About с действием Index.
hyde

Вы можете определить сервер функций на бритве, например: @functions { public bool IsActive(string action, string controller) { var actionRoute = ViewContext.RouteData.Values["Action"].ToString(); var controlRoute = ViewContext.RouteData.Values["Controller"].ToString(); return controller.Equals(controlRoute)&& actionRoute.Equals(actionRoute); } }и использование: <li class="@(IsActive("Index", "Home")? "active": "")">
Хуа Чунг

2

Мы также можем создавать UrlHelperиз RequestContext, который мы можем получить из самого MvcHandler. Поэтому я верю, что тот, кто хочет сохранить эту логику в шаблонах Razor, будет полезен следующим образом:

  1. В корне проекта создайте папку с именем AppCode.
  2. Создайте там файл с именем HtmlHelpers.cshtml
  3. Создайте там помощника:

    @helper MenuItem(string action, string controller)
    {
         var mvcHandler = Context.CurrentHandler as MvcHandler;
         if (mvcHandler != null)
         {
             var url = new UrlHelper(mvcHandler.RequestContext);
             var routeData = mvcHandler.RequestContext.RouteData;
             var currentAction = routeData.Values["action"].ToString();
             var currentController = routeData.Values["controller"].ToString();
             var isCurrent = string.Equals(currentAction, action, StringComparison.InvariantCultureIgnoreCase) &&
                             string.Equals(currentController, controller, StringComparison.InvariantCultureIgnoreCase);
    
            <div class="@(isCurrent ? "active" : "")">
                <div>@url.Action(action, controller)</div>
            </div>
         }   
    }
  4. Затем мы можем использовать в наших представлениях вот так:

    @HtmlHelpers.MenuItem("Default", "Home")

Надеюсь, что это кому-то поможет.


Это действительно круто. Есть ли здесь недостатки в производительности?
давка

@crush, я не измерял это, но я ожидал, что это будет иметь низкое влияние на производительность, потому что я думаю, что структура использует аналогичную логику для создания, UrlHelperкоторая есть у вас Controller.Url. Единственное, что мы, вероятно, не хотим выполнять создание UrlHelperдля каждого вызова, MenuItemпоэтому мы можем применить отметку сохранения его в HttpContext Items после первого вызова помощника, чтобы мы делали это только один раз для каждого запроса.
Алексей Аза

2

возможно с лямбда-функцией

@{
string controllerAction = ViewContext.RouteData.Values["Controller"].ToString() + ViewContext.RouteData.Values["Action"].ToString();
    Func<string, string> IsSelected= x => x==controllerAction ? "active" : "";
}

затем использование

 @Html.ActionLink("Inicio", "Index", "Home", new { area = "" }, new { @class = IsSelected("HomeIndex")})

2

Я создал HtmlHelperрасширение, которое добавляет ActiveActionLinkметод для тех из вас, кто хочет добавить «активный» класс к самой ссылке, а не к <li>окружающему ссылку.


public static class LinkExtensions
{
    public static MvcHtmlString ActiveActionLink(this HtmlHelper html, string linkText, string actionName, string controllerName, object routeValues, object htmlAttributes)
    {
        return ActiveActionLink(html, linkText, actionName, controllerName, new RouteValueDictionary(routeValues), HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
    }

    public static MvcHtmlString ActiveActionLink(this HtmlHelper html, string linkText, string actionName, string controllerName, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes)
    {
        const string activeClassName = "active";

        var routeData = html.ViewContext.RouteData;

        var routeAction = (string)routeData.Values["action"];
        var routeController = (string)routeData.Values["controller"];

        var active = controllerName.Equals(routeController) && actionName.Equals(routeAction);

        if (active)
        {
            var @class = (string)htmlAttributes["class"];

            htmlAttributes["class"] = string.IsNullOrEmpty(@class)
                ? activeClassName
                : @class + " active";
        }

        var link = html.ActionLink(linkText, actionName, controllerName, routeValues, htmlAttributes);

        return link;
    }
}

Использование следующее:

@Html.ActiveActionLink("Home", "Index", "Home", new { area = "" }, new { @class = "nav-item nav-link" })

1

ответ @dombenoit работает. Хотя он вводит некоторый код для обслуживания. Проверьте этот синтаксис:

using (var nav = Html.Bootstrap().Begin(new Nav().Style(NavType.NavBar).SetLinksActiveByControllerAndAction()))
{
    @nav.ActionLink("Link 1", "action1")
    @nav.ActionLink("Link 2", "action2")
    @nav.Link("External Link", "#")
}

Обратите внимание на использование .SetLinksActiveByControllerAndAction()метода.

Если вам интересно, что делает этот синтаксис возможным, посмотрите TwitterBootstrapMVC


Спасибо за ответ, Дмитрий, я тестирую TwitterBootstrapMVC
Гиллеспи

1

Я тоже искал решение, и jQuery мне очень помог. Во-первых, вам нужно присвоить своим <li>элементам идентификаторы .

<li id="listguides"><a href='/Guides/List'>List Guides</a></li>

Сделав это на странице макета, вы можете указать jQuery, какой <li>элемент должен быть «выбран» в вашем представлении.

@section Scripts{
    <script type="text/javascript">
        $('#listguides').addClass('selected');
    </script>
}

Примечание: вам необходимо иметь @RenderSection("scripts", required: false)на своем макете страницу непосредственно перед </body>тегом, чтобы добавить этот раздел.


1

Я хотел бы предложить это решение, основанное на первой части ответа Дома.

Сначала мы определяем две переменные, «действие» и «контроллер», и используем их для определения активной ссылки:

{ string controller = ViewContext.RouteData.Values["Controller"].ToString();
string action = ViewContext.RouteData.Values["Action"].ToString();}

А потом:

<ul class="nav navbar-nav">
    <li class="@((controller == "Home" && action == "Index") ? "active" : "")">@Html.ActionLink("Home", "Index", "Home")</li>
    <li class="@((controller == "Home" && action == "About") ? "active" : "")">@Html.ActionLink("About", "About", "Home")</li>
    <li class="@((controller == "Home" && action == "Contact") ? "active" : "")">@Html.ActionLink("Contact", "Contact", "Home")</li>
</ul>

Теперь это выглядит лучше и не требует более сложных решений.


0

если он вообще не отображается, причина в том, что вам нужно два знака @:

@@class

НО, я считаю, что вам может понадобиться активный класс в теге «li», а не в теге «a». согласно слишком бутстраповские документы ( http://getbootstrap.com/components/#navbar-default ):

<ul class="nav navbar-nav">
  <li class="active"><a href="#">Home</a></li>
  <li><a href="#">Profile</a></li>
  <li><a href="#">Messages</a></li>
</ul>

поэтому ваш код будет:

<ul class="nav navbar-nav">
  <li class="active">@Html.ActionLink("Home", "Index", "Home", null)</li>
  <li>@Html.ActionLink("About", "About", "Home")</li>
  <li>@Html.ActionLink("Contact", "Contact", "Home")</li>
</ul>

Класс @@ выдает ошибку, у меня изначально был ваш пример кода выше, который работает, но не совсем так, как Actionlinks «должны» быть?
Гиллеспи

изм. @@ не требуется. вы должны поставить класс на EA
JC Lizard

0

Надеюсь, это поможет, вот каким может быть ваше меню:

 <ul class="nav navbar-nav">
   <li><a href="@Url.Action("Index", "Home")" class="@IsMenuSelected("Index","Home", "active")">Home</a></li>
   <li><a href="@Url.Action("About", "Home")" class="@IsMenuSelected("About", "Home", "active")">About</a></li>
   <li><a href="@Url.Action("Contact", "Home")" class="@IsMenuSelected("Contact", "Home", "active")">Contact</a></li>
 </ul>

И добавьте вспомогательную функцию MVC под тегом html.

 @helper IsMenuSelected(string actionName, string controllerName, string className)
    {
            var conname = ViewContext.RouteData.Values["controller"].ToString().ToLower();
            var actname = ViewContext.RouteData.Values["action"].ToString().ToLower();

            if (conname == controllerName.ToLower() && actname == actionName.ToLower())
        {
            @className;
        }
    }

Я сослался на ответ http://questionbox.in/add-active-class-menu-link-html-actionlink-asp-net-mvc/


0

Я понял, что эта проблема - обычная проблема для некоторых из нас, поэтому я опубликовал собственное решение с использованием пакета nuget. Ниже вы можете увидеть, как это работает. Надеюсь, это будет полезно.

Примечание. Этот пакет nuget - мой первый пакет. Так что если вы заметили ошибку, оставьте отзыв. Спасибо.

  1. Установите пакет или загрузите исходный код и добавьте свой проект

    -Install-Package Betalgo.MvcMenuNavigator
  2. Добавьте свои страницы в перечисление

    public enum HeaderTop
    {
        Dashboard,
        Product
    }
    public enum HeaderSub
    {
        Index
    }
  3. Поместите фильтр в верхнюю часть вашего Controllor или Action

    [MenuNavigator(HeaderTop.Product, HeaderSub.Index)]
    public class ProductsController : Controller
    {
        public async Task<ActionResult> Index()
        {
            return View();
        }
    
        [MenuNavigator(HeaderTop.Dashboard, HeaderSub.Index)]
        public async Task<ActionResult> Dashboard()
        {
            return View();
        }
    }
  4. И используйте его в макете заголовка, как это

    @{
    var headerTop = (HeaderTop?)MenuNavigatorPageDataNavigatorPageData.HeaderTop;
    var headerSub = (HeaderSub?)MenuNavigatorPageDataNavigatorPageData.HeaderSub;
    }
    <div class="nav-collapse collapse navbar-collapse navbar-responsive-collapse">
    <ul class="nav navbar-nav">
        <li class="@(headerTop==HeaderTop.Dashboard?"active selected open":"")">
            <a href="@Url.Action("Index","Home")">Dashboard</a>
        </li>
        <li class="@(headerTop==HeaderTop.Product?"active selected open":"")">
            <a href="@Url.Action("Index", "Products")">Products</a>
        </li>
    </ul>

Дополнительная информация: https://github.com/betalgo/MvcMenuNavigator


0

Я считаю, что вот более чистый и компактный код, чтобы сделать выбранное меню «активным»:

 <ul class="navbar-nav mr-auto">
                <li class="nav-item @Html.IfSelected("Index")">
                    <a class="nav-link" href="@Url.Action("Index", "Home")">Home</a>
                </li>
                <li class="nav-item @Html.IfSelected("Controls")">
                    <a class="nav-link" href="@Url.Action("Controls", "Home")">MVC Controls</a>
                </li>
                <li class="nav-item @Html.IfSelected("About")">
                    <a class="nav-link" href="@Url.Action("About", "Home")">About</a>
                </li>
</ul>

 public static string IfSelected(this HtmlHelper html, string action)
        {
            return html
                       .ViewContext
                       .RouteData
                       .Values["action"]
                       .ToString() == action
                            ? " active"
                            : "";
        }

Приятно, хотя, вероятно, в некоторых случаях может потребоваться расширение на контроллер и зону
planetClaire

-1

Я сделал комбинацию ответов выше и сделал свое решение.

Так..

Сначала в блоке razor создайте одну строковую переменную, которая будет содержать значение имени контроллера и действие, вызываемое пользователем.

    @{
        string controllerAction =  ViewContext.RouteData.Values["Controller"].ToString() + ViewContext.RouteData.Values["Action"].ToString(); 
    }

Затем используйте комбинацию кода HTML и Razor:

    <ul class="nav navbar-nav">
        <li class="@(controllerAction == "HomeIndex" ? "active" : "" )">@Html.ActionLink("Home", "Index", "Home")</li>
        <li class="@(controllerAction == "AboutIndex" ? "active" : "" )">@Html.ActionLink("About", "Index", "About")</li>
        <li class="@(controllerAction == "HomeContact" ? "active" : "" )">@Html.ActionLink("Contact", "Contact", "Home")</li>
    </ul>

Я думаю, что это хорошо, потому что вам не нужно каждый раз обращаться к «ViewContext.RouteData.Values», чтобы получить имя контроллера и имя действия.


-1

Мое решение этой проблемы

<li class="@(Context.Request.Path.Value.ToLower().Contains("about") ? "active " : "" ) nav-item">
                <a class="nav-link" asp-area="" asp-controller="Home" asp-action="About">About</a>
            </li>

Лучшим способом может быть добавление метода расширения Html для возврата текущего пути для сравнения со ссылкой.


-1

Я сделал это:

Добавлен помощник в частичном представлении меню

 @helper RouterLink(string action, string controller)
{
    var IsActive = ViewContext.RouteData.Values["Controller"].ToString() == controller && ViewContext.RouteData.Values["Action"].ToString() == action;
    <text>href="@Url.Action(action, controller)"</text>if (IsActive){ <text>class="active"</text>}
}

Затем использовал его в теге привязки следующим образом:

<li><a @RouterLink("Index","Home")>Home</a></li>

В моем приложении не было областей, но его также можно включить в качестве другой переменной во вспомогательную функцию. И мне пришлось передать активный класс тегу привязки, на мой взгляд. Но liможно и так настроить.


1
Понимаете, отрицательное голосование не поможет, если вы не укажете причину.
Ануп Шарма
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.