Як додати "активний" клас до Html.ActionLink в ASP.NET MVC


128

Я намагаюся додати "активний" клас до мого bootstrap navbar в 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
код, який вирішує, має в ньому клас = active. Це не те, що ви хочете сказати у своєму запитанні? Як у вас є ваш код, як я додаю класи
Мет Боділі

ви не надто зрозумілі !!! Я точно не розумію, у чому проблема, додавши його до нави, хоча я відчуваю, що так і має бути добре
JC Lizard

1
У чому проблема з вирішеним кодом? Що ви очікуєте? Чи можете ви бути більш конкретними, ніж "не здається, що працює"? Ваше запитання недостатньо чітке, щоб допомогти вам прямо зараз.
dom

Відредаговано! Вибачте, я мав на увазі те, що "активний" клас взагалі не показується
Gillespie

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.04.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>

Дякую, як я вже згадував, як це було у мене спочатку, але я сподівався мати один метод у всьому моєму коді зміни класу "активний" між вибраними об'єктами.
Gillespie

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

5
Що стосується першого редагування, воно фактично працювало лише для сторінки "Індекс". Здається, причина полягає в тому, що коли він робив порівняння, він не вдався, оскільки ViewContext.RouteData.Values ​​["Дія"] не повертає об'єкт типу String (досі не знаю, як він працював на першій сторінці ....) . Коли я змінив усі ViewContext.RouteData.Values ​​["Дія"] на ViewContext.RouteData.Values ​​["Дія"]. ToString (), він працював на всіх сторінках. Можливо, ви хочете додати це у своєму рішенні на випадок, якщо хтось відчуває ту саму проблему.
користувач3281466

2
@LonelyPixel, можливо, ця відповідь працює для вас?
dom

1
Для користувачів VB.NET: <li class = "@ (Якщо (ViewContext.RouteData.Values ​​(" Дія "). ToString () =" Індекс "," Активний "," "))"> @ Html.ActionLink (" Головна "," Індекс "," Головна ") </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

@ René Kåbis це для завантаження завантажувача getbootstrap.com/components/#nav-tabs
Проф.

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

Я керував цим, додавши параметр пакета перегляду в mpc asp.net. Ось що я зробив

Додано ViewBag.Current = "Scheduler";як параметр на кожній сторінці

На сторінці макета

<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 робить); отже, нічого не виводиться, навіть клас = "". Я думаю, що це чистіше і для ремонту, і для чистоти. Я прагну завжди завжди залишати логіку поза зоною, наскільки це можу.


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

Я змінив відповідь дому "не дуже" і зробив його більш бридким. Іноді два контролери мають суперечливі назви дій (тобто індекс), тому я роблю це:

<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
Дуже вдале рішення. Як у вашому прикладі я можу встановити "Контакт" як активний за замовчуванням?
Пані Суман Кабір

1
Дякую. Хороша річ у тому, що вам не потрібно встановлювати активний елемент. Щойно сторінку «Контакт» відвідано, ActiveActionLink()буде застосовано активний клас до <li>:-)
WoIIe

де ти перевіряєш область?
Мохаммед

@Mohammad я не розумію. Чи можете ви, будь ласка, розробити своє запитання?
WoIIe

у класі LinkExtensions ви не отримали область від routeData!
Мохаммед

3

Легкий 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>

-


Це не спрацює, якщо в двох різних контролерах є однакові назви дій. Перевірте це за допомогою домашніх та про контролерів з дією Index.
Гайд

Ви могли б визначити функціональний сервер на бритві, як: @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": "")">
Hua Trung

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
Gillespie

1

Я також шукав рішення, і jQuery дуже допоміг. По-перше, вам потрібно надати 'id' своїм <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?
Gillespie

відредаговано. @@ не потрібно. ви повинні поставити клас на 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. Нижче ви можете побачити, як це працює. Сподіваюсь, це стане в нагоді.

Примітка. Цей пакунок-нукет - це мій перший пакет. Тож якщо ви бачите помилку, будь ласка, дайте відгуки. Дякую.

  1. Встановіть пакет або завантажте вихідний код та додайте свій проект

    -Install-Package Betalgo.MvcMenuNavigator
  2. Додайте свої сторінки до переліку

    public enum HeaderTop
    {
        Dashboard,
        Product
    }
    public enum HeaderSub
    {
        Index
    }
  3. Поставте фільтр у верхній частині свого контролера чи дії

    [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

Я склав комбінацію відповідей вище і прийняв своє рішення.

Так..

Спочатку в блоці бритви створіть одну рядкову змінну, яка буде містити значення імені контролера та дії, що викликається користувачем.

    @{
        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
Розумієте, downvote не дуже допомагає, якщо ви не згадаєте причину.
Anup Sharma
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.