asp.net-mvc MVC 与 Bootstrap 导航栏 - 将所选项目设置为活动

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/22407367/
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-09-08 03:35:34  来源:igfitidea点击:

MVC with Bootstrap Navbar - Set Selected Item to Active

asp.net-mvctwitter-bootstraptwitter-bootstrap-3

提问by Big Daddy

I'm learning Bootstrap and can't get the selected item into an "active" state. The active state remains on the default item. The newly selected/clicked item changes to active briefly, but reverts back. I've read all the posts and still can't get this code to work. I'm using MVC5 and JQuery 2.1.

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

EDIT:If I change the li's hrefs to href="#", then the active class gets applied properly. What's happening when a new view gets loaded? I think Sebastian's response is close, but gets messy with Areas.

编辑:如果我将 li 的 hrefs 更改为href="#",则活动类将被正确应用。加载新视图时会发生什么?我认为 Sebastian 的回应很接近,但对 Areas 变得混乱。

Markup

标记

<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

脚本

<script type="text/javascript">

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

</script>

EDIT:Here's what I ended up doing with the help of the posted answers and some research.

编辑:这是我最终在发布的答案和一些研究的帮助下所做的。

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

回答by SebastianStehle

You have to check in your controller or view which menu item is active based on the current url:

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

I have an extension method similar to this:

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

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

You can use it in your view like this:

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

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

回答by Jeff Walker Code Ranger

The JavaScript isn't working because the page is getting reloaded after it runs. So it correctly sets the active item and then the page loads because the browser is following the link. Personally, I would remove the JavaScript you have because it serves no purpose. To do this client side (instead of the server side code you have), you need JavaScript to set the active item when the new page loads. Something like:

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

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

I recommend adding an id or other class to your navbar so you can be sure you have selected the correct one.

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

回答by Mahib

Simplest thing to do is send a ViewBag parameter from your controllers like following;

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

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


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

In the cshtml page do the following;

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

Courtesy to @Damith in here

感谢@Damith 在这里

回答by Moji

Simply you can do this in any view

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

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

After you add this method to a new class or existing HtmlExtensions class

将此方法添加到新类或现有 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));
    }
}

回答by tlbignerd

I believe you have the selection backward. You're adding the class, then removing it from the siblings, and I think doing the remove second is causing the issue. Can you try reversing this to be:

我相信你的选择落后了。您正在添加类,然后从兄弟姐妹中删除它,我认为删除第二个是导致问题的原因。您可以尝试将其反转为:

<script type="text/javascript">

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

</script>

回答by jmyns

Your javascript function should work fine... The issue is that your links route to a controller and reload the entire page. In order to avoid this behavior you could render your body content as a partial view, that way the navbar elements do not reload. You shouldn't have to write a function to handle dom events - that is what javascript is for.

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

To see what I mean, change your code:

要了解我的意思,请更改您的代码:

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

to:

到:

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