【问题标题】:How to add "active" class to Html.ActionLink in ASP.NET MVC如何在 ASP.NET MVC 中向 Html.ActionLink 添加“活动”类
【发布时间】:2013-12-23 00:29:45
【问题描述】:

我正在尝试在 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 的正确方法。还有另一种(整洁的)方法可以做到这一点吗?

【问题讨论】:

  • 解析的代码中包含 class= active。这不是你说的你想要的问题吗?你如何拥有你的代码就是我如何添加类
  • 你不太清楚!!!我不完全明白将它添加到导航有什么问题,即使我有一种感觉,它的方式应该很好
  • 解决的代码有什么问题?你在期待什么?你能比“似乎不起作用”更具体吗?您的问题还不够清楚,目前无法为您提供帮助。
  • 已编辑!抱歉,我的意思是“活动”类根本没有显示
  • 刚刚浏览了 Bootstrap 的文档,我认为您需要将 active 类添加到 li 元素,而不是 a。请参阅此处的第一个示例:getbootstrap.com/components/#navbar

标签: asp.net css asp.net-mvc twitter-bootstrap


【解决方案1】:

在 Bootstrap 中,active 类需要应用于&lt;li&gt; 元素,而不是&lt;a&gt;。请参阅此处的第一个示例: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>

编辑:

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

最简单的方法是简单地使用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>

它的代码并不漂亮,但它可以完成工作并允许您根据需要将菜单提取到局部视图中。有一些方法可以以更简洁的方式做到这一点,但既然你才刚刚开始,我就先把它留在那里。祝您学习 ASP.NET MVC 好运!


后期编辑:

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

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

适用于 .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 不用担心!我已经编辑了我的答案,以添加一些可能对您有所帮助的信息。
  • 关于第一次编辑,它实际上只适用于索引页面。似乎原因是当它进行比较时,它失败了,因为 ViewContext.RouteData.Values["Action"] 没有返回 String 类型的对象(仍然不知道它在第一页是如何工作的......) .当我将所有 ViewContext.RouteData.Values["Action"] 更改为 ViewContext.RouteData.Values["Action"].toString() 时,它适用于所有页面。可能想在您的解决方案中添加它,以防万一有人遇到同样的问题。
  • @LonelyPixel 也许this answer 适合你?
  • 对于 VB.NET 用户:
  • @Html.ActionLink("Home", "Index", "Home")
【解决方案2】:

扩展名:

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)。无序列表是一组相关链接的非常合适的容器,因为它将它们以逻辑方式组合在一起。
  • @René Kåbis 用于引导导航getbootstrap.com/components/#nav-tabs
  • 当用户手动输入小写字母或大写字母的url时,这不起作用,例如。 “domain.com/Login”和“domain.com/LOGIN”。对于解决方案,var str = String.Format("&lt;li role=\"presentation\"{0}&gt;{1}&lt;/li&gt;", currentAction.toLower().Equals(action.toLower(), StringComparison.InvariantCulture) &amp;&amp; currentController.toLower().Equals(controller.toLower(), StringComparison.InvariantCulture) ? " class=\"active\"" : String.Empty, html.ActionLink(text, action, controller).ToHtmlString() );
【解决方案3】:

我设法通过在 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>

这解决了我的问题。

【讨论】:

【解决方案4】:

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

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得到参考

【讨论】:

【解决方案5】:

简单的 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">

【讨论】:

  • 是的,这对我有用,但子列表有问题。我已经放了,但是页面刷新后它没有继续扩展我的列表。
      • 产品
      • 类别
  • 对于第一级它工作正常,但第二级 ul 不起作用
  • 仅供参考,您只需执行以下操作即可替换 if、else 和 SetAttribute: output.MergeAttributes(new TagBuilder("li").AddCssClass("active"));
【解决方案6】:

ASP.NET Core & Bootstrap 4

最新答案

我重新设计了 @crush 的简洁解决方案,以更新的、ASP.NET CoreBootstrap 4 兼容的方式来解决此问题,基于 @ 987654322@扩展方法:

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>

【讨论】:

  • 非常好的解决方案。在您的示例中,我如何将“联系人”默认设置为活动状态?
  • 谢谢。好处是您不需要设置活动元素。访问“联系”页面后,ActiveActionLink() 会将活动类应用于&lt;li&gt; :-)
  • 你在哪里检查区域?
  • 在 LinkExtensions 类中你没有从 routeData 获得区域!
  • 如果您要将 nav-itemactive Bootstrap 类硬编码到您的帮助程序中,您不妨也将 nav-link 类硬编码到其中,以便您不需要每次都指定:new { @class = "nav-link" }.
【解决方案7】:

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

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

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>

当您导航到其他页面时,例如 Programs,ViewBag.Home 不存在(而 ViewBag.Programs 存在);因此,没有渲染任何内容,甚至没有渲染 class=""。我认为这对于可维护性和清洁度来说都更干净。我总是想尽可能地把逻辑排除在视图之外。

【讨论】:

    【解决方案8】:

    考虑到 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>
    

    【讨论】:

    • 干净高效!
    【解决方案9】:

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

    1. 创建一个静态类,例如Utilitarios.cs

    2. 在Class里面创建一个静态方法:

      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>
      

    【讨论】:

      【解决方案10】:

      我创建了一个HtmlHelper 扩展,为那些想要将“活动”类添加到链接本身而不是链接周围的&lt;li&gt; 的人添加了一个ActiveActionLink 方法。

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

      【讨论】:

        【解决方案11】:

        我修改了dom's"not pretty" answer,让它变得更丑了。有时两个控制器有冲突的动作名称(即索引),所以我这样做:

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

        【讨论】:

          【解决方案12】:

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

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

          【讨论】:

            【解决方案13】:

            可以使用 lambda 函数

            @{
            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")})
            

            【讨论】:

              【解决方案14】:

              关于这个问题的大多数解决方案都要求您在 li a(通过 HtmlHelper)标签上指定“页面”。 @Wolles@Crush 的答案都消除了这种重复,这很好,但他们使用的是 HtmlHelper 扩展方法而不是 TagHelpers。我想使用 TagHelper 支持 Razor 页面。

              您可以阅读my full post here(并获取源代码),但它的要点是:

              &lt;bs-menu-link asp-page="/Events/Index" menu-text="Events"&gt;&lt;/bs-menu-link&gt;

              将呈现(如果链接明显处于活动状态):

              &lt;li class="active"&gt;&lt;a href="/Events"&gt;Events&lt;/a&gt;&lt;/li&gt;

              我的 TagHelper 在内部利用 AnchorTagHelper(因此支持 asp-page、asp-controller、asp-action 等属性)。活动与否的“检查”与本文的许多答案相似。

              【讨论】:

              • 我真的很喜欢你的回答。你值得点赞!
              【解决方案15】:

              添加 '.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 操作进行测试。
              • 你可以在剃须刀上定义功能服务器,例如:@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)&amp;&amp; actionRoute.Equals(actionRoute); } } 和用法:&lt;li class="@(IsActive("Index", "Home")? "active": "")"&gt;
              【解决方案16】:

              我们也可以从 RequestContext 创建UrlHelper,我们可以从 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 中一样。唯一的问题是,我们可能不想为每次调用 MenuItem 执行创建 UrlHelper,因此我们可能会在第一次调用助手后将其保存到 HttpContext Items 中,因此我们每次请求只执行一次.
              【解决方案17】:

              @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

              【讨论】:

              • 感谢 Dmitry 的回答,我正在测试 TwitterBootstrapMVC
              【解决方案18】:

              我也在寻找解决方案,而 jQuery 帮助很大。首先,您需要为您的&lt;li&gt; 元素提供“id”。

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

              在您的布局页面中执行此操作后,您可以告诉 jQuery 在您的视图中应该“选择”哪个 &lt;li&gt; 元素。

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

              注意:您需要在布局页面中添加 @RenderSection("scripts", required: false),在 &lt;/body&gt; 标记之前添加该部分。

              【讨论】:

                【解决方案19】:

                我想根据 Dom 的回答的第一部分提出这个解决方案。

                我们首先定义两个变量,“action”和“controller”,并使用它们来确定活动链接:

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

                现在它看起来更好,不需要更复杂的解决方案。

                【讨论】:

                  【解决方案20】:

                  我意识到这个问题对我们中的一些人来说是一个常见问题,所以我使用 nuget 包发布了我自己的解决方案。下面你可以看到它是如何工作的。我希望这会有用。

                  注意:这个 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

                  【讨论】:

                    【解决方案21】:

                    我相信这是一个更简洁、更简洁的代码,可以让所选菜单处于“活动状态”:

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

                    【讨论】:

                    • 不错,虽然在某些情况下可能需要针对控制器和区域进行扩展
                    【解决方案22】:

                    我找到了适用于多条路线的解决方案。 标记助手:

                    [HtmlTargetElement("li", Attributes = "active-when")]
                        public class ActiveTagHelper : TagHelper
                        {
                            [HtmlAttributeName("active-when")]
                            public string ActiveWhen { get; set; }
                    
                            [ViewContext]
                            [HtmlAttributeNotBound]
                            public ViewContext ViewContext { get; set; }
                    
                            public override void Process(TagHelperContext context, TagHelperOutput output)
                            {
                                if (ActiveWhen == null)
                                    return;
                    
                                var hrefs = ActiveWhen.Split(",");
                    
                                var currentController = ViewContext.RouteData.Values["controller"].ToString();
                                var currentAction = ViewContext.RouteData.Values["action"].ToString();
                    
                                foreach (var item in hrefs)
                                {
                                    var targetController = item.Split("/")[1];
                                    var targetAction = item.Split("/")[2];
                    
                                    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");
                                        }
                                    }
                                }
                            }
                        }
                    

                    进口:

                    @addTagHelper *, YourProjectName
                    

                    用法:

                       <li class="nav-item" active-when="/Product/Index,/Product/Add"></li>
                    

                    【讨论】:

                      【解决方案23】:

                      在布局页面的顶部,

                      @{ var _path = Context.Request.Path.ToString();}
                      

                      在您的导航栏中,

                      <a class="nav-link dropdown-toggle @(_path.Contains("UTBulkFlights") ? "active" : "")">abcLink</a>
                      

                      【讨论】:

                        【解决方案24】:

                        如果根本不显示,原因是你需要两个@符号:

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

                        【讨论】:

                        • @@class 抛出错误,我最初有上面的代码示例,它可以工作,但不完全像 Actionlinks“应该”那样吗?
                        • 已编辑。 @@ 不是必需的。你必须把课程放在 EA 上
                        【解决方案25】:

                        我已经组合了上面的答案并提出了我的解决方案。

                        所以..

                        首先在 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”来获取控制器名称和操作名称。

                        【讨论】:

                          【解决方案26】:

                          我对这个问题的解决方案是

                          <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 扩展方法来返回当前路径以与链接进行比较

                          【讨论】:

                            【解决方案27】:

                            我这样做了:

                            在菜单部分视图中做了一个助手

                             @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也可以这样配置。

                            【讨论】:

                            • 你看,如果你不提及原因,downvote 并没有真正的帮助。
                            【解决方案28】:

                            ASP.NET Core & Bootstrap 4 & AdminLte

                            [HtmlTargetElement("a", Attributes = "active-then")]
                            [HtmlTargetElement("a", Attributes = "asp-action")]
                            [HtmlTargetElement("a", Attributes = "asp-controller")]
                            public class AnchorActiveTagHelper : AnchorTagHelper
                            {
                                public AnchorActiveTagHelper(IHtmlGenerator generator) : base(generator)
                                {
                                }
                            
                                [HtmlAttributeName("active-then")]
                                public string ActiveWhen { get; set; }
                            
                                [ViewContext] [HtmlAttributeNotBound] public ViewContext ViewContextData { get; set; }
                            
                                public override void Process(TagHelperContext context, TagHelperOutput output)
                                {
                                    base.Process(context, output);
                                    
                                    if (ActiveWhen == null)
                                        return;
                            
                                    var currentController = ViewContextData.RouteData.Values["controller"].ToString();
                                    var currentAction = ViewContextData.RouteData.Values["action"].ToString();
                            
                                    if (currentController.Equals(Controller) && currentAction.Equals(Action))
                                    {
                                        if (output.Attributes.ContainsName("class"))
                                        {
                                            output.Attributes.SetAttribute("class", $"{output.Attributes["class"].Value} active");
                                        }
                                        else
                                        {
                                            output.Attributes.SetAttribute("class", "active");
                                        }
                                    }
                                }
                            }    
                            

                            @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
                            @removeTagHelper Microsoft.AspNetCore.Mvc.TagHelpers.AnchorTagHelper, Microsoft.AspNetCore.Mvc.TagHelpers
                            @addTagHelper *, YourProject.PlatformExtensions
                            

                            用法

                            <li class="nav-item">
                                <a asp-controller="Home" asp-action="Index" class="nav-link" active-then="active">
                                   <i class="nav-icon fas fa-home"></i>
                                   <p>Home</p>
                                </a>
                            </li>
                            

                            感谢@WoIIe 和@Shahab

                            【讨论】:

                              猜你喜欢
                              相关资源
                              最近更新 更多
                              热门标签