ASP.NET MVC菜单选定项

时间:2011-01-11 01:04:06

标签: asp.net asp.net-mvc

MVC新手。我之前问了this问题并得到了答案,但我想知道是否有更简单的解决方案。

假设我有一个母版页,其菜单列为无序列表。我如何在当前选择的菜单项上设置css类?

编辑:

当您启动新的mvc应用程序时,我正在使用菜单,因为它是开箱即用的设置

<ul id="menu">              
   <li><%: Html.ActionLink("Home", "Index", "Home")%></li>
   <li><%: Html.ActionLink("About", "About", "Home")%></li>
</ul>

7 个答案:

答案 0 :(得分:27)

Jakub Konecki的回答让我朝着正确的方向前进......这是我最终得到的控制器动作:

    [ChildActionOnly]
    public ActionResult MainMenu()
    {
        var items = new List<MenuItem>
        {
            new MenuItem{ Text = "Home", Action = "Index", Controller = "Home", Selected=false },
            new MenuItem{ Text = "My Profile", Action = "Index", Controller = "Profile", Selected = false},
            new MenuItem{ Text = "About", Action = "About", Controller = "Home", Selected = false }
        };

        string action = ControllerContext.ParentActionViewContext.RouteData.Values["action"].ToString();
        string controller = ControllerContext.ParentActionViewContext.RouteData.Values["controller"].ToString();

        foreach (var item in items)
        {
            if (item.Controller == controller && item.Action == action)
            {
                item.Selected = true;
            }
        }

        return PartialView(items);
    }

希望这有助于某人。

答案 1 :(得分:18)

您应该传递模型中的所有相关信息。理想情况下,您的菜单将通过单独的控制器方法呈现为部分视图。我有一个导航控制器,其中包含MainMenu,FooterMenu,Breadcrumbs等操作,可以渲染各个部分。

您的模型将是以下菜单项的集合:

    public class MenuItemModel
    {
        public MenuItemModel()
        {
            SubMenu = new List<MenuItemModel>();
        }

        public string Text { get; set; }
        public string Controller { get; set; }            
        public string Action { get; set; }
        public bool Selected { get; set; }

        public List<MenuItemModel> SubMenu { get; private set; }
    }

您的控制器将创建一个菜单项集合,并将它们传递给视图,并选择相应的项目。然后视图可以简单:

<ul id="menu">     
    <% foreach(var menuItem in Model.MenuItems) { %> 
        <li><%: Html.ActionLink(menuItem.Text, menuItem.Action, menuItem.Controller, null, new { @class = menuItem.Selected ? "selected" : "" })%></li>
    <% } %>
</ul>

答案 2 :(得分:4)

斯蒂芬,

这是我对党的贡献。一个递归内联函数,用于填充<ul><li>所需的深度(这是整个ascx文件):

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<List<GBC_Art.Controllers.MenuItemModel>>" %>
<%@ Import Namespace="GBC_Art.Controllers" %>
<%
    Action<List<MenuItemModel>, int> printNodesRecursively = null;
    printNodesRecursively = (List<MenuItemModel> nodeList, int depth) =>
    {
        if (nodeList == null || nodeList.Count == 0) return;
%>
    <ul<%= depth == 0 ? " id='menu'" : ""%>>  
<%
    foreach (var menuItem in nodeList)
    {
    %>
    <li><%= Html.ActionLink(menuItem.Text, menuItem.Action, menuItem.Controller, null, new { @class = menuItem.Selected ? "selected" : "" })%>
        <%printNodesRecursively(menuItem.SubMenu, depth + 1);%>
    </li>
    <%
        }
%>
    </ul>
<%
    };
    List<MenuItemModel> nodes = Model; 
    printNodesRecursively(nodes, 0);
%>

用法 - &gt;根据上面的例子,通过控制器调用部分视图。

欢呼声

答案 3 :(得分:4)

这是另一种可能性,我认为使用HTML Helper更简单:

CSS类

ul#menu li.selected a {
  background-color: #034af3;
  color: #e8eef4;
}

HTML Helper

using System;
using System.Collections.Generic;
using System.Web;
using System.Web.Mvc;

namespace MyWebApp.WebUI.HtmlHelpers
{
  public static class HtmlHelperExtensions
  {
    public static string ActivePage(this HtmlHelper helper, string controller, string action)
    {
      string classValue = "";

      string currentController = helper.ViewContext.Controller.ValueProvider.GetValue("controller").RawValue.ToString();
      string currentAction = helper.ViewContext.Controller.ValueProvider.GetValue("action").RawValue.ToString();

      if (currentController == controller && currentAction == action)
      {
        classValue = "selected";
      }

      return classValue;
    }
  }
}

布局上的菜单

<nav>
  <ul id="menu">
    <li class="@Html.ActivePage("Home", "Index")">@Html.ActionLink("Home", "Index", "Home")</li>
    <li class="@Html.ActivePage("Home", "About")">@Html.ActionLink("About", "About", "Home")</li>
  </ul>
</nav>

此处有更多信息:http://bubblogging.wordpress.com/2012/02/12/mvc-add-selected-class-to-menu/

答案 4 :(得分:2)

现在只是学习MVC,但我遇到了这个问题,我想出了一个更快的方法来实现这个目标。它依赖于一致的URL,不受查询字符串的影响。

<ul id="menu">              
  <li @(Request.Path.Equals("/") ? Html.Raw("class=\"selected\"") : Html.Raw(""))>
    @Html.ActionLink("Home", "Index", "Home")</li>
  <li @(Request.Path.Equals("/about") ? Html.Raw("class=\"selected\"") : Html.Raw(""))>
    @Html.ActionLink("About", "About", "Home")%></li>
</ul>

当然,您可以处理多个网址,显示通过OR逻辑或列表选择的相同项目。但如果你正在制作一个清单,你当然希望在你的模型中。只需检查字符串的开头是否匹配,就可以为整个目录选择一个选项。

原样,这最适合更静态的网站。如果将其包含在LayoutPage中,则维护非常简单,因为您没有要维护的额外类或函数。显然,如果你在CMS工作,这不会削减它。

答案 5 :(得分:1)

除了所有其他解决方案之外,您还可以使用此方法从数据库动态加载菜单,并使所选菜单处于活动状态并保持网站状态。

布局页面中的

<body>
<header>
   @{Html.RenderPartial("_MenuPartial"); }
</header>
@RenderBody()
</body>

然后你的局部视图包含:

<nav class="navMain">
<ul>
   foreach (var menu in menuList)
   {
    <li id="@menu.Id"><a href="@menu.Url">@menu.Name</a></li>
   }
</ul>
</nav>

要激活单击的菜单,您需要在局部视图中使用脚本。除了改变CSS中的背景颜色外,还有“活跃”类。

<script>
var selector = '.navMain li';
$(selector).on('click', function () {
    $(this).addClass('active').siblings().removeClass('active');
    var menuId = $(this).prop("id");
    localStorage.setItem('SelectedMenu', menuId);
});

由于我们为每个菜单链接设置了HREF,因此每个回发都会丢失活动类。因此,您需要从localStorage中读取所选菜单,并将其应用于部分视图中的正确菜单:

<script>
$(document).ready(function () {
    var activeMenuLocalStorage = localStorage.getItem('SelectedMenu');
    if (!isNaN(activeMenuLocalStorage)) {
    {
     $("#" + activeMenuLocalStorage).addClass('active');
    }
});

答案 6 :(得分:0)

editOrderContainer = jasmine.createSpyObj('editOrderContainer', ['getEditOrderState', 'rebookOrder']); editOrderContainer.getEditOrderState.and.callFake(() => { var editOrderState = getOrderDetailsServiceResult(); return Observable.of(editOrderState); }); function getOrderDetailsServiceResult() { return { data: { shipAddressEdited: true, shipInstructionEditted: true } }; } 时最简单的方法..感谢@HugoHilário的概​​念

you don't want to change your code much

布局页面

using Microsoft.Web.Mvc;     
using System.Web.Mvc;
using System.Web.Mvc.Html;

namespace Demo.Web.Mvc
{
    public static class UIHelper
    {             
        public static MvcHtmlString ActivePage(this HtmlHelper helper, string linkText, string action, string controller)
        { 
            string currentController = helper.ViewContext.Controller.ValueProvider.GetValue("controller").RawValue.ToString();
            string currentAction = helper.ViewContext.Controller.ValueProvider.GetValue("action").RawValue.ToString();    

            var actionLink = helper.ActionLink(linkText, action,controller);
            var isCurrentRoute = currentController == controller;// && currentAction == action; uncomment if you want to segregate by action also

            return MvcHtmlString.Create(string.Format("<li{0}>", isCurrentRoute ? " class=\"YourActiveCssClass\"" : string.Empty) + actionLink + "</li>");    

        }
    }
}