CSS 如何在 ASP.NET MVC 中向 Html.ActionLink 添加“活动”类

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20410623/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 01:12:16  来源:igfitidea点击:

How to add "active" class to Html.ActionLink in ASP.NET MVC

asp.netcssasp.net-mvctwitter-bootstrap

提问by Gillespie

I'm trying to add an"active" class to my bootstrap navbar in MVC, but the following doesn't show the active class when written like this:

我正在尝试向 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>

This resolves to what looks like a correctly formatted class, but doesn't work:

这解析为看起来像格式正确的类,但不起作用:

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

In the Bootstrap documentation it states that 'a' tags shouldn't be used in the navbar, but the above is how I believe is the correct way of adding a class to an Html.ActionLink. Is there another (tidy) way I can do this?

在 Bootstrap 文档中,它指出不应在导航栏中使用“a”标签,但以上是我认为将类添加到 Html.ActionLink 的正确方法。有没有另一种(整洁的)方法可以做到这一点?

回答by dom

In Bootstrap the activeclass needs to be applied to the <li>element and not the <a>. See the first example here: http://getbootstrap.com/components/#navbar

在 Bootstrap 中,active类需要应用于<li>元素而不是<a>. 请参阅此处的第一个示例:http: //getbootstrap.com/components/#navbar

The way you handle your UI style based on what is active or not has nothing to do with ASP.NET MVC's ActionLinkhelper. This is the proper solution to follow how the Bootstrap framework was built.

您根据活动与否处理 UI 样式的方式与 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>


Edit:

编辑:

Since you will most likely be reusing your menu on multiple pages, it would be smart to have a way to apply that selected class automatically based on the current page rather than copy the menu multiple times and do it manually.

由于您很可能会在多个页面上重复使用您的菜单,因此有一种方法可以根据当前页面自动应用所选的类,而不是多次复制菜单并手动执行。

The easiest way is to simply use the values contained in ViewContext.RouteData, namely the Actionand Controllervalues. We could build on what you currently have with something like this:

最简单的方法是简单地使用包含在 中的值ViewContext.RouteData,即ActionController值。我们可以在您目前拥有的基础上使用以下内容:

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

It's not pretty in code, but it'll get the job done and allow you to extract your menu into a partial view if you like. There are ways to do this in a much cleaner way, but since you're just getting started I'll leave it at that. Best of luck learning ASP.NET MVC!

它的代码并不漂亮,但它可以完成工作并允许您根据需要将菜单提取到部分视图中。有很多方法可以以更简洁的方式执行此操作,但是由于您才刚刚开始,因此我将保留它。祝您学习 ASP.NET MVC 好运!



Late edit:

后期编辑:

This question seems to be getting a bit of traffic so I figured I'd throw in a more elegant solution using an HtmlHelperextension.

这个问题似乎有点流量,所以我想我会使用HtmlHelper扩展程序提供更优雅的解决方案。

Edit 03-24-2015: Had to rewrite this method to allow for multiple actions and controllers triggering the selected behavior, as well as handling for when the method is called from a child action partial view, thought I'd share the update!

2015 年 3 月 24 日编辑:必须重写此方法以允许多个动作和控制器触发所选行为,以及处理从子动作部分视图调用该方法的时间,我想我会分享更新!

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;
}

Works with .NET Core:

适用于 .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;
}

Sample usage:

示例用法:

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

回答by Prof

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);
}

Usage:

用法:

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

回答by Damith

I manged to do this by adding a view bag parameter in asp.net mvc. Here what have i done

我设法通过在 asp.net mvc 中添加一个视图包参数来做到这一点。在这里我做了什么

Added ViewBag.Current = "Scheduler";like parameter in each page

ViewBag.Current = "Scheduler";在每个页面中添加了like参数

In layout page

在布局页面

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

This solved my problem.

这解决了我的问题。

回答by Virag Dilip Desai

May be little late. But hope this helps.

可能会晚一点。但希望这会有所帮助。

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" : "";
    }
}

And usage as follow:

用法如下:

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

Got reference from http://www.codingeverything.com/2014/05/mvcbootstrapactivenavbar.html

http://www.codingeverything.com/2014/05/mvcbootstrapactivenavbar.html得到参考

回答by mapussah

I know this question is old, but I will just like to add my voice here. I believe it is a good idea to leave the knowledge of whether or not a link is active to the controller of the view.

我知道这个问题很老,但我只想在这里添加我的声音。我相信将链接是否处于活动状态的知识留给视图的控制器是一个好主意。

I would just set a unique value for each view in the controller action. For instance, if I wanted to make the home page link active, I would do something like this:

我只会为控制器操作中的每个视图设置一个唯一值。例如,如果我想让主页链接处于活动状态,我会这样做:

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

Then in my view, I will write something like this:

那么在我看来,我会这样写:

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

When you navigate to a different page, say Programs, ViewBag.Home does not exist (instead ViewBag.Programs does); therefore, nothing is rendered, not even class="". I think this is cleaner both for maintainability and cleanliness. I tend to always want to leave logic out of the view as much as I can.

当你导航到一个不同的页面时,比如 Programs,ViewBag.Home 不存在(取而代之的是 ViewBag.Programs);因此,什么都不渲染,甚至 class="" 也不渲染。我认为这对于可维护性和清洁度来说都更清洁。我倾向于总是尽可能地将逻辑排除在视图之外。

回答by Rafe Smith

Considering what Damith posted, I like to think you can just qualify active by the Viewbag.Title(best practice is to populate this in your content pages allowing your _Layout.cshtmlpage to hold your link bars). Also note that if you are using sub-menu itemsit also works fine:

考虑到 Damith 发布的内容,我认为您可以通过Viewbag.Title来限定 active (最佳做法是在您的内容页面中填充它,允许您的_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>

回答by Deyvi Javier Saavedra Garcia

This solution is simple for Asp.net MCV 5.

这个解决方案对于 Asp.net MCV 5 来说很简单。

  1. Create a static class, for example Utilitarios.cs.

  2. Inside the Class create a static method:

    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. call like this

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

回答by DeveloperDan

I modified dom's"not pretty" answerand made it uglier. Sometimes two controllers have the conflicting action names (i.e. Index) so I do this:

我修改了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 atik sarker

You can try this: In my case i am loading menu from database based on role based access, Write the code on your every view which menu your want to active based on your view.

你可以试试这个:在我的情况下,我正在根据基于角色的访问从数据库加载菜单,在你的每个视图上编写代码,你想根据你的视图激活哪个菜单。

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

回答by henoc salinas

is possible with a lambda function

可以使用 lambda 函数

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

then usage

然后使用

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