Я пытаюсь добавить "активный" класс в мой 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. Есть ли другой (аккуратный) способ, которым я могу это сделать?
В Bootstrap active
класс должен применяться к элементу <li>
а не к <a>
. См. Первый пример здесь: http://getbootstrap.com/components/#navbar
Способ, которым вы обрабатываете свой стиль пользовательского интерфейса, в зависимости от того, что является активным или нет, не имеет ничего общего с помощником ASP.NET MVC ActionLink
. Это правильное решение, чтобы следить за тем, как была создана структура 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
.
Редактирование 03-24-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>
Extension:
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>
role="presentation"
, которая совсем не подходит для основного навигационного меню ( john.foliot.ca/aria-hidden/#pr ). Неупорядоченный список является подходящим контейнером для связанного набора ссылок, поскольку он логически группирует их.
Мне удалось сделать это, добавив параметр мешка просмотра в asp.net mvc. Вот что я сделал
Добавлен 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>
Это решило мою проблему.
Может быть, немного поздно. Но надеюсь, что это поможет.
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
Я знаю, что этот вопрос старый, но я просто хочу добавить свой голос здесь. Я считаю, что неплохо оставить информацию о том, активна ли связь с контроллером представления.
Я бы просто установил уникальное значение для каждого представления в действии контроллера. Например, если бы я хотел активировать ссылку домашней страницы, я бы сделал что-то вроде этого:
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= "". Я думаю, что это чище как для ремонтопригодности, так и для чистоты. Я, как правило, всегда хочу оставить логику из взгляда настолько, насколько я могу.
Это решение просто для Asp.net MCV 5.
Создайте статический класс, например Utilitarios.cs
.
Внутри класса создайте статический метод:
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 "";
}
назовите это
<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>
Вы можете попробовать следующее: В моем случае я загружаю меню из базы данных на основе доступа, основанного на ролях, напишите код на каждом вашем представлении, какое меню вы хотите активно на основе вашего представления.
<script type="text/javascript">
$(document).ready(function () {
$('li.active active-menu').removeClass('active active-menu');
$('a[href="/MgtCustomer/Index"]').closest('li').addClass('active active-menu');
});
</script>
возможно с помощью лямбда-функции
@{
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")})
Добавьте '.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>
-
@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": "")">
Я понял, что эта проблема была обычной проблемой для некоторых из нас, поэтому я опубликовал собственное решение, используя пакет nuget. Ниже вы можете увидеть, как это работает. Надеюсь, это будет полезно.
Примечание. Этот пакет nuget - это мой первый пакет. Поэтому, если вы видите ошибку, пожалуйста, сообщите об этом. Спасибо.
Установите пакет или загрузите исходный код и добавьте свой проект
-Install-Package Betalgo.MvcMenuNavigator
Добавьте свои страницы в перечисление
public enum HeaderTop
{
Dashboard,
Product
}
public enum HeaderSub
{
Index
}
Поместите фильтр в начало вашего 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();
}
}
И используйте его в своем макете заголовка, как это
@{
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
Я изменил 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>
ответ by @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
Я считаю, что здесь есть более чистый и маленький код, чтобы сделать выбранное меню "активным":
<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"
: "";
}
Учитывая то, что опубликовал Damith, мне нравится думать, что вы можете просто квалифицироваться активным с помощью 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>
Мое решение этой проблемы -
<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 для возврата текущего пути к сравнению с ссылкой
Я сделал комбинацию ответов выше и сделал свое решение.
Итак..
Сначала в блоке бритвы создайте одну строковую переменную, которая будет содержать значение имени контроллера и действие, которое вызывается пользователем.
@{
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", чтобы получить имя контроллера и имя действия.
Я хотел бы предложить это решение, основанное на первой части ответа Dom.
Сначала мы определяем две переменные: "действие" и "контроллер" и используем их для определения активной ссылки:
{ 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>
Теперь он выглядит лучше и не нуждается в более сложных решениях.
Надеюсь, что это поможет, ниже показано, как ваше меню может быть:
<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/
Я также искал решение, и 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>
.
Мы также можем создать UrlHelper
из RequestContext, который мы можем получить от самого MvcHandler. Поэтому я верю, что кто-то, кто хочет сохранить эту логику в шаблонах Razor следующим образом, будет полезен:
AppCode
.HtmlHelpers.cshtml
Создайте там помощника:
@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>
}
}
Затем мы можем использовать на наших представлениях так:
@HtmlHelpers.MenuItem("Default", "Home")
Надеюсь, что это помогает кому-то.
UrlHelper
, который есть в Controller.Url
. Единственное, что мы, вероятно, не хотим выполнять создание UrlHelper
для каждого вызова MenuItem
поэтому мы можем применить галочку для сохранения его в элементах HttpContext после первого вызова помощника, поэтому мы делаем это только один раз для каждого запроса.
если это вообще не отображается, причина в том, что вам нужно два знака @:
@@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>