使用引导导航栏的MVC -将选定的项目设置为活动

时间:2022-11-03 20:02:40

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的反应很接近,但是在一些方面有点混乱。

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

6 个解决方案

#1


27  

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>

#2


15  

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或其他类,这样您就可以确保您选择了正确的类。

#3


6  

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在这里报道

#4


5  

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

将此方法添加到新类或现有的htmlextense类之后

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

#5


1  

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>

#6


0  

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函数应该可以正常工作……问题是您的链接路由到一个控制器并重新加载整个页面。为了避免这种行为,您可以将body内容呈现为局部视图,这样导航条元素就不会重载。您不需要编写一个函数来处理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>

#1


27  

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>

#2


15  

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或其他类,这样您就可以确保您选择了正确的类。

#3


6  

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在这里报道

#4


5  

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

将此方法添加到新类或现有的htmlextense类之后

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

#5


1  

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>

#6


0  

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函数应该可以正常工作……问题是您的链接路由到一个控制器并重新加载整个页面。为了避免这种行为,您可以将body内容呈现为局部视图,这样导航条元素就不会重载。您不需要编写一个函数来处理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>