带有引导导航栏的 MVC - 将所选项目设置为活动

Posted

技术标签:

【中文标题】带有引导导航栏的 MVC - 将所选项目设置为活动【英文标题】:MVC with Bootstrap Navbar - Set Selected Item to Active 【发布时间】:2014-04-19 21:13:00 【问题描述】:

我正在学习 Bootstrap,无法将所选项目置于“活动”状态。活动状态保持在默认项目上。新选择/单击的项目会短暂变为活动状态,但会恢复。我已阅读所有帖子,但仍然无法使此代码正常工作。我正在使用 MVC5 和 JQuery 2.1。

编辑: 如果我将 li 的 href 更改为 href="#",则活动类将正确应用。加载新视图时会发生什么?我认为塞巴斯蒂安的反应很接近,但对区域很混乱。

标记

<div class="navbar-wrapper">
    <div class="container">
        <div class="navbar navbar-inverse navbar-fixed-top">

            <div class="navbar-header">
                <a class="navbar-toggle" data-toggle="collapse" data-target=".nav-collapse">
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </a>
                <a class="navbar-brand" href="#">Test</a>
            </div>
            <div class="btn-group pull-right">
                <a class="btn dropdown-toggle" data-toggle="dropdown" href="#">
                    <i class="icon-user"></i>Login
          <span class="caret"></span>
                </a>
                <ul class="dropdown-menu">
                    <li><a href="#">Profile</a></li>
                    <li class="divider"></li>
                    <li><a href="#">Sign Out</a></li>
                </ul>
            </div>
            <div class="navbar-collapse collapse">
                <ul class="nav navbar-nav">
                    <li class="active"><a href="~/Home">Home</a></li>
                    <li><a href="~/Home/About">About</a></li>
                    <li><a href="~/Student">Students Sample</a></li>
                    <li class="dropdown">
                        <a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown <b class="caret"></b></a>
                        <ul class="dropdown-menu">
                            <li><a href="~/Admin/Home/Index"">Admin</a></li>
                            <li><a href="#">Another action</a></li>
                            <li><a href="#">Something else here</a></li>
                            <li class="divider"></li>
                            <li><a href="#">Separated link</a></li>
                            <li><a href="#">One more separated link</a></li>
                        </ul>
                    </li>
                </ul>
            </div>

        </div>
    </div>
    <!-- /container -->
</div>
<!-- /navbar wrapper -->

脚本

<script type="text/javascript">

    $(function () 
        $('.navbar-nav li').click(function () 
            $(this).addClass('active').siblings().removeClass('active');
        );
    );

</script>

编辑: 这是我在发布的答案和一些研究的帮助下最终完成的工作。

public static string MakeActive(this UrlHelper urlHelper,string action, string controller, string area = "")
        
            string result = "active";
            string requestContextRoute;
            string passedInRoute;

            // Get the route values from the request           
            var sb = new StringBuilder().Append(urlHelper.RequestContext.RouteData.DataTokens["area"]);
            sb.Append("/");
            sb.Append(urlHelper.RequestContext.RouteData.Values["controller"].ToString());
            sb.Append("/");
            sb.Append(urlHelper.RequestContext.RouteData.Values["action"].ToString());
            requestContextRoute = sb.ToString();

            if (string.IsNullOrWhiteSpace(area))
            
                passedInRoute = "/" + controller + "/" + action;
            
            else
            
                passedInRoute = area + "/" + controller + "/" + action;
            

            //  Are the 2 routes the same?
            if (!requestContextRoute.Equals(passedInRoute, StringComparison.OrdinalIgnoreCase))
            
                result = null;
            

            return result;
        

【问题讨论】:

您是否为这个 BigDaddy 找到了明确的解决方案?我一直想给某人打电话……特别是。汉斯·帕桑特! @Killercam...看看我的编辑。它显示了我的想法。这是公认答案的扩展。 【参考方案1】:

使用代码from here 的简化版本,如果控制器和动作匹配(或者如果没有提供动作,则只标记控制器),您可以使用标签助手将锚标记为“活动”。

导航:

  <li class="nav-item px-2">
       <a class="nav-link" asp-active-route asp-controller="Home" asp-action="Index">Home</a>
  </li>
  <li class="nav-item px-2">
       <a class="nav-link" asp-active-route asp-controller="Car" asp-action="Add">Add Car</a>
   </li>

标签助手类

[htmlTargetElement(Attributes = "asp-active-route")]
public class ActiveRouteTagHelper : TagHelper

    [HtmlAttributeName("asp-controller")] public string Controller  get; set; 

    [HtmlAttributeName("asp-action")] public string Action  get; set; 

    [HtmlAttributeNotBound] [ViewContext] public ViewContext ViewContext  get; set; 

    public override void Process(TagHelperContext context, TagHelperOutput output)
    
        if (IsActive())
        
            output.AddClass("active", HtmlEncoder.Default);
        

        output.Attributes.RemoveAll("asp-active-route");

        base.Process(context, output);
    

    private bool IsActive()
    
        var currentController = ViewContext.RouteData.Values["Controller"].ToString();
        var currentAction = ViewContext.RouteData.Values["Action"].ToString();
        var active = false;

        if (!string.IsNullOrWhiteSpace(Controller) && !string.IsNullOrWhiteSpace(currentController))
        
            active = Controller.Equals(currentController, StringComparison.CurrentCultureIgnoreCase);

            if (active && !string.IsNullOrWhiteSpace(Action) && !string.IsNullOrWhiteSpace(currentAction))
            
                active = Action.Equals(currentAction, StringComparison.CurrentCultureIgnoreCase);
            
        

        return active;
    

不要忘记将标签助手添加到您的 _ViewImports.cshtml

 @addTagHelper *, My.Awesome.Web
未来的改进将是检查区域并可能将整个导航包裹在控件/助手中,这样您只需比较一次路线并标记项目

【讨论】:

【参考方案2】:

只需添加这个 JQuery 编码:

<script>
        $(document).ready(function () 
            $('body').find('a[href="' + location.pathname + '"]')
                .addClass('active');
        );
</script>

【讨论】:

【参考方案3】:

您可以在任何视图中执行此操作

<ul class="nav navbar-nav">
    @Html.NavigationLink("Link1", "Index", "Home")
    @Html.NavigationLink("Link2", "Index", "Home")
    @Html.NavigationLink("Link3", "Index", "Home")
    @Html.NavigationLink("Links with Parameter", "myAction", "MyController", new id=999, new  @class= " icon-next" )
</ul>

将此方法添加到新类或现有 HtmlExtensions 类后

public static class HtmlExtensions

    public static MvcHtmlString NavigationLink(this HtmlHelper html, string linkText, string action, string controller, object routeValues=null, object css=null)
    
        TagBuilder aTag = new TagBuilder("a");
        TagBuilder liTag = new TagBuilder("li");
        var htmlAttributes = HtmlHelper.AnonymousObjectToHtmlAttributes(css);
        string url = (routeValues == null)?
            (new UrlHelper(html.ViewContext.RequestContext)).Action(action, controller)
            :(new UrlHelper(html.ViewContext.RequestContext)).Action(action, controller, routeValues);

        aTag.MergeAttribute("href", url);
        aTag.InnerHtml = linkText;
        aTag.MergeAttributes(htmlAttributes);

        if (action.ToLower() == html.ViewContext.RouteData.Values["action"].ToString().ToLower() && controller.ToLower() == html.ViewContext.RouteData.Values["controller"].ToString().ToLower())
            liTag.MergeAttribute("class","active");

        liTag.InnerHtml = aTag.ToString(TagRenderMode.Normal);
        return new MvcHtmlString(liTag.ToString(TagRenderMode.Normal));
    

【讨论】:

记得把@using yourNamespace放在你的视图中。就我而言,我把它放在我的视图布局_Layout.cshtml 如何使用此方法进行下拉?【参考方案4】:

最简单的做法是从您的控制器发送一个 ViewBag 参数,如下所示;

public ActionResult About()
                
        ViewBag.Current = "About";
        return View();
    


    public ActionResult Contact()
                
        ViewBag.Current = "Contact";
        return View();
    

在cshtml页面中执行以下操作;

           <ul class="nav navbar-nav">                    
                <li class="@(ViewBag.Current == "About" ? "active" : "")">@Html.ActionLink("About", "About", "Home")</li>
                <li class="@(ViewBag.Current == "Contact" ? "active" : "")">@Html.ActionLink("Contact", "Contact", "Home")</li>
            </ul>

感谢@Damith here

【讨论】:

【参考方案5】:

JavaScript 不工作,因为页面在运行后重新加载。所以它正确设置了活动项目,然后页面加载,因为浏览器正在跟踪链接。就个人而言,我会删除您拥有的 JavaScript,因为它没有任何用途。要执行此客户端(而不是您拥有的服务器端代码),您需要 JavaScript 在新页面加载时设置活动项。就像是:

$(document).ready(function() 
    $('ul.nav.navbar-nav').find('a[href="' + location.pathname + '"]')
        .closest('li').addClass('active');
);

我建议您在导航栏中添加一个 id 或其他类,这样您就可以确定您选择了正确的。

【讨论】:

这就是我要找的! 谢谢!但是如何将上一个菜单项恢复为原始颜色(非活动) 对我来说很好用,也很简单。 JoshYates1980,不会有回发吗?如果不是,您可以在设置新课程之前删除所有活动课程。 谢谢!这就是我要找的。所有的程序员之神都会保佑你!【参考方案6】:

您的 javascript 函数应该可以正常工作...问题是您的链接路由到控制器并重新加载整个页面。为了避免这种行为,您可以将正文内容呈现为部分视图,这样导航栏元素就不会重新加载。您不必编写函数来处理 dom 事件——这就是 javascript 的用途。

要明白我的意思,请更改您的代码:

<li><a href="~/Home/About">About</a></li>
<li><a href="~/Student">Students Sample</a></li>

到:

 <li><a href="">About</a></li>
 <li><a href="">Students Sample</a></li>

【讨论】:

【参考方案7】:

您必须检查您的控制器或根据当前 url 查看哪个菜单项处于活动状态:

我有一个类似这样的扩展方法:

public static string MakeActiveClass(this UrlHelper urlHelper, string controller)

    string result = "active";

    string controllerName = urlHelper.RequestContext.RouteData.Values["controller"].ToString();

    if (!controllerName.Equals(controller, StringComparison.OrdinalIgnoreCase))
    
        result = null;
    

    return result;

您可以像这样在视图中使用它:

<!-- Make the list item active when the current controller is equal to "blog" -->
<li class="@Url.MakeActive("blog")">
   <a href="@Url.Action("index", "blog")">....</a>
</li>

【讨论】:

假设我有同名的控制器,因为它们位于区域中? 在这种情况下,您还必须检查该区域。很奇怪,但是你可以使用:object areaName = urlHelper.RequestContext.RouteData.DataTokens["area"] 谢谢,但应该有比这更干净的东西,对吧? 我并不喜欢这个解决方案,但它似乎是做这种事情的方式 - 根据我的研究。 只是一个小错字,扩展方法名应该是MakeActive而不是MakeActiveClass。【参考方案8】:

我相信你的选择是倒退的。您正在添加课程,然后将其从兄弟姐妹中删除,我认为第二次删除会导致问题。您可以尝试将其反转为:

<script type="text/javascript">

    $(function () 
        $('.navbar-nav li').click(function () 
            $(this).siblings().removeClass('active');
            $(this).addClass('active');
        );
    );

</script>

【讨论】:

谢谢,但我得到了同样的行为 您还有其他对导航栏起作用的事件吗?您是否可以在 jsfiddle 中重现该问题? 没有其他事件。我从视图中发布所有代码。 因为方法链,他的脚本和你的一样。他的问题是他的链接请求一个新页面,当页面重新加载时活动项丢失了。

以上是关于带有引导导航栏的 MVC - 将所选项目设置为活动的主要内容,如果未能解决你的问题,请参考以下文章

Silverlight Combobox 将所选项目设置为 datagrid 的所选项目

将所选项目从上下文菜单发送到另一个活动

将所选选项显示为 Html 和 JavaScript 中的引导下拉菜单

将数据从活动传递到底部导航栏的片段

在移动设备中查看时带有侧边栏的 Bootstrap 导航栏

颤振多选可搜索下拉菜单,将所选项目作为芯片添加到字段中