如何将"active"类添加到ASP.NET MVC中的Html.ActionLink

Gil*_*pie 117 css asp.net asp.net-mvc twitter-bootstrap

我正在尝试在MVC中向我的bootstrap导航栏中添加一个"活动"类,但是以下内容在显示时不会显示活动类:

<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>
Run Code Online (Sandbox Code Playgroud)

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

<a class="active" href="/">Home</a>
Run Code Online (Sandbox Code Playgroud)

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

dom*_*dom 278

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

基于活动与否的方式处理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>
Run Code Online (Sandbox Code Playgroud)

编辑:

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

最简单的方法是简单地使用包含的值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>
Run Code Online (Sandbox Code Playgroud)

它在代码中并不漂亮,但它可以完成工作,并允许您根据需要将菜单提取到局部视图中.有一些方法可以更清洁的方式做到这一点,但既然你刚刚开始我会留下它.祝你好运学习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;
}
Run Code Online (Sandbox Code Playgroud)

适用于.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;
}
Run Code Online (Sandbox Code Playgroud)

样品用法:

<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>
Run Code Online (Sandbox Code Playgroud)

  • 关于第一次编辑,它实际上只适用于索引页面.似乎原因是当它进行比较时,它失败了,因为ViewContext.RouteData.Values ["Action"]没有返回一个String类型对象(仍然不知道它是如何工作的第一页......) .当我将所有ViewContext.RouteData.Values ["Action"]更改为ViewContext.RouteData.Values ["Action"].toString()时,它适用于所有页面.可能希望在您的解决方案中添加此项,以防有人遇到相同的问题. (5认同)
  • @Gillespie不用担心!我编辑了我的答案,添加了一些可能对您有所帮助的信息. (2认同)
  • @LonelyPixel可能[这个答案](http://stackoverflow.com/a/27257593/380096)适合你吗? (2认同)

小智 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);
}
Run Code Online (Sandbox Code Playgroud)

用法:

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

  • 一个美丽.好一个. (2认同)

Dam*_*ith 18

我通过在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>
Run Code Online (Sandbox Code Playgroud)

这解决了我的问题.


Vir*_*sai 12

可能会迟到一点.但希望这会有所帮助.

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" : "";
    }
}
Run Code Online (Sandbox Code Playgroud)

用法如下:

<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>
Run Code Online (Sandbox Code Playgroud)

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


Gui*_*lva 12

简单的 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");
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

包含到您的 _ViewImports.cs 中:

@addTagHelper *, YourAssemblyName
Run Code Online (Sandbox Code Playgroud)

用法:

 <li active-when="/Home/Index">
Run Code Online (Sandbox Code Playgroud)


WoI*_*IIe 7

ASP.NET Core & Bootstrap 4

Most up-to-date answer

I have re-worked @crush's neat solution for an updated, ASP.NET Core and Bootstrap 4 compatible way to solve this problem based on an IHtmlHelper extension method:

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());
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Usage

<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>
Run Code Online (Sandbox Code Playgroud)


map*_*sah 6

我知道这个问题已经过时了,但我想在这里加上我的声音.我认为将链接是否处于活动状态的知识留给视图的控制器是个好主意.

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

public ActionResult Index()
{            
    ViewBag.Title = "Home";
    ViewBag.Home = "class = active";
    return View();
}
Run Code Online (Sandbox Code Playgroud)

然后在我看来,我会写这样的东西:

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

导航到其他页面时,例如程序,ViewBag.Home不存在(而不是ViewBag.Programs); 因此,没有任何东西被渲染,甚至不是class ="".我认为这对于可维护性和清洁度来说都更清洁.我倾向于总是希望尽可能多地将逻辑排除在视野之外.