2011-01-18 20 views
64

He estado explorando tratando de encontrar una solución adecuada para asignar clases "activas/actuales" a elementos de menú de la página maestra. La línea se divide en el medio con respecto a si hacer este lado del cliente vs servidor.elemento de menú activo - asp.net mvc3 página maestra

A decir verdad soy nuevo en JavaScript y MVC, así que no tengo una opinión. Preferiría hacer esto de la manera "más limpia" y más apropiada.

Tengo el siguiente código jQuery para asignar la clase "activa" al elemento <li> ... el único problema es que el elemento de menú "índice" o vista predeterminada siempre tendrá asignada la clase activa, porque la URL siempre es una subcadena de los otros enlaces del menú:

(default) index = localhost/ 
link 1 = localhost/home/link1 
link 2 = localhost/home/link1 

$(function() { 
var str = location.href.toLowerCase(); 
    $('#nav ul li a').each(function() { 
    if (str.indexOf(this.href.toLowerCase()) > -1) { 
    $(this).parent().attr("class","active"); //hightlight parent tab 
    } 
}); 

¿hay una mejor manera de hacer esto, chicos? Al menos alguien me ayudaría a obtener la versión del cliente a prueba de balas? ¿Para que el "índice" o enlace predeterminado siempre esté "activo"? ¿Hay alguna forma de asignar una extensión falsa al método de índice? ¿en lugar de solo la URL base sería localhost/home/dashboard para que no sea una subcadena de cada enlace?

A decir verdad, realmente no sigo los métodos de este lado del servidor, por lo que trato de hacerlo desde el lado del cliente con jQuery ... cualquier ayuda sería apreciada.

Respuesta

114

Un ayudante HTML personalizada por lo general hace el trabajo muy bien:

public static MvcHtmlString MenuLink(
    this HtmlHelper htmlHelper, 
    string linkText, 
    string actionName, 
    string controllerName 
) 
{ 
    string currentAction = htmlHelper.ViewContext.RouteData.GetRequiredString("action"); 
    string currentController = htmlHelper.ViewContext.RouteData.GetRequiredString("controller"); 
    if (actionName == currentAction && controllerName == currentController) 
    { 
     return htmlHelper.ActionLink(
      linkText, 
      actionName, 
      controllerName, 
      null, 
      new { 
       @class = "current" 
      }); 
    } 
    return htmlHelper.ActionLink(linkText, actionName, controllerName); 
} 

y en su página maestra:

<ul> 
    <li>@Html.MenuLink("Link 1", "link1", "Home")</li> 
    <li>@Html.MenuLink("Link 2", "link2", "Home")</li> 
</ul> 

Ahora todo lo que queda es definir la clase .Current CSS.

+27

Merece la pena señalar que htmlHelper.ActionLink() necesita "usar System.Web.Mvc.Html;" – 4imble

+1

Funciona de forma brillante +1 – 4imble

+5

También necesita importar el espacio de nombres en su vista, si usa Razor en MVC3 puede hacerlo simplemente agregando @using a su vista – Duncan

-1

Lo que suelo hacer es asignar una clase a la etiqueta del cuerpo basada en las partes de la ruta. Entonces, si haces un String, reemplaza la ruta para convertir/blogs/posts/1 a class = "blogs posts 1".

A continuación, puede asignar reglas CSS para manejar eso. Por ejemplo, si tiene un elemento de menú para "blogs", sólo puede hacer una regla como

BODY.blogs li.blogs { /* your style */} 

o si desea un estilo particular si su en un poste único vicio si se encuentra en la raíz del blog página

BODY.blogs.posts li.blogs {/* your style */} 
+1

loco por esta solución ... requiere la creación de una clase para cada elemento del menú, ¿no? – Michael

4

Aquí está mi solución de este problema.

creé siguiente método de extensión de la clase HtmlHelper:

public static class HtmlHelpers 
{ 
    public static string SetMenuItemClass(this HtmlHelper helper, string actionName) 
    { 
     if (actionName == helper.ViewContext.RouteData.Values["action"].ToString()) 
      return "menu_on"; 
     else 
      return "menu_off"; 
    } 

entonces tengo mi menublock. Se ve así:

<div id="MenuBlock"> 
    <div class="@Html.SetMenuItemClass("About")"> 
     <a>@Html.ActionLink("About", "About", "Home")</a></div> 
    <img height="31" width="2" class="line" alt="|" src="@Url.Content("~/Content/theme/images/menu_line.gif")"/> 
    <div class="@Html.SetMenuItemClass("Prices")"> 
     <a>@Html.ActionLink("Prices", "Prices", "Home")</a></div> 
</div> 

Así que mi método devuelve nombre de clase a cada Div de acuerdo a la acción actual del controlador principal. Puede profundizar y agregar al método un parámetro, que especifica el nombre del controlador para evitar problemas, cuando tiene acciones con el mismo nombre pero con diferentes controladores.

5

ha añadido soporte para las áreas:

public static class MenuExtensions 
{ 
    public static MvcHtmlString MenuItem(this HtmlHelper htmlHelper, string text, string action, string controller, string area = null) 
    { 

     var li = new TagBuilder("li"); 
     var routeData = htmlHelper.ViewContext.RouteData; 

     var currentAction = routeData.GetRequiredString("action"); 
     var currentController = routeData.GetRequiredString("controller"); 
     var currentArea = routeData.DataTokens["area"] as string; 

     if (string.Equals(currentAction, action, StringComparison.OrdinalIgnoreCase) && 
      string.Equals(currentController, controller, StringComparison.OrdinalIgnoreCase) && 
      string.Equals(currentArea, area, StringComparison.OrdinalIgnoreCase)) 
     { 
      li.AddCssClass("active"); 
     } 
     li.InnerHtml = htmlHelper.ActionLink(text, action, controller, new {area}, null).ToHtmlString(); 
     return MvcHtmlString.Create(li.ToString()); 
    } 
} 
2

A través de jQuery u puede hacer así:

$(document).ready(function() { 
    highlightActiveMenuItem(); 
}); 

highlightActiveMenuItem = function() { 
    var url = window.location.pathname; 
    $('.menu a[href="' + url + '"]').addClass('active_menu_item'); 
}; 

.active_menu_item { 
    color: #000 !important; 
    font-weight: bold !important; 
} 

original: http://www.paulund.co.uk/use-jquery-to-highlight-active-menu-item

Cuestiones relacionadas