2011-01-11 6 views
20

OK новый для MVC. Я задал вопрос this и получил ответ, но мне интересно, есть ли более простое решение.Меню ASP.NET MVC Выбранный элемент

Скажем, у меня есть главная страница с меню, выложенным как неупорядоченный список. Как я могу настроить класс css в текущем выбранном пункте?

EDIT:

Я использую меню так же, как она идет установка из коробки, когда вы начинаете новый Mvc App

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

Как вы генерацию меню? – jfar

+0

@jfar - код добавлен – stephen776

+0

Смущенный нисходящим потоком ... его основной вопрос, конечно, самопровозглашенным новичком MVC. Просто ищем небольшое руководство по этому вопросу. – stephen776

ответ

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

Надеется, что это помогает кто то.

+2

+1 - спасибо Stephen. смотрел на это сам вчера, и это было очень полезно. Кстати, вы в конечном итоге использовали html.renderpartial или renderaction для этого? Кроме того, вы размещаете частичное представление на своей главной странице? –

+0

Не сейчас перед моей машиной, но я уверен, что пошел с рендерингом на главной странице – stephen776

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

Но как бы добавить класс 'selected' к ссылке, которая ссылается на текущую страницу ... кажется, что ваше решение всегда будет применять класс к первому элементу списка ... – stephen776

+1

Отредактировано ответ –

+0

У меня это работает по большей части. Мне было интересно, если у вас будет пример контроллера для этого. Мое меню работает. Я просто не понимаю, как установить выбранный элемент в контроллере ... – stephen776

4

stephen,

вот мой вклад в партию. рекурсивная функция инлайн для заполнения <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); 
%> 

использование -> называется как PartialView через контроллер, как в вашем примере выше.

веселит

+0

awesome ... это будет следующим в моем списке. Спасибо за вклад – stephen776

+0

, вероятно, это будет вики или что-то еще, так как это будет распространенной проблемой для тех, кто новичок в MVC, таких как я, – stephen776

+0

, возможно, вы ошибаетесь. если он движется, помните, чтобы поднять ответ, поскольку они не учитываются в вики :-) –

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/

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> 

Конечно, вы можете обрабатывать несколько URL-адресов, показывающие один и тот же элемент, выбранный с помощью OR логики или составления списка. Но если вы составляете список, вы, конечно, хотите этого в своей модели. Вы можете выделить опцию для всего каталога, просто проверив, что начало строки соответствует.

Как это было бы лучше всего подходит для более статического веб-сайта. Если вы включите это в LayoutPage, обслуживание будет довольно простым, так как у вас нет дополнительных классов или функций для поддержки. Очевидно, это не сократило бы его, если бы вы работали над CMS.

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

Смежные вопросы