2009-09-24 14 views
17

Como base para la discusión. Cree un proyecto web ASP.NET MVC estándar.¿Cómo se indica visualmente la página actual en ASP.NET MVC?

Contendrá dos elementos de menú en la página maestra:

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

¿Cómo puedo configurar el estilo CSS visual que indica la página actual. Por ejemplo, cuando en la página Acerca de/controlador, que básicamente me gustaría hacer esto:

<%= Html.ActionLink("About", "About", "Home", new {class="current"})%></li> 

Y, por supuesto, cuando en la página principal:

<%= Html.ActionLink("Home", "Index", "Home", new {class="current"})%></li> 

(Tener un estilo CSS nombres actuales que indican visualmente en el menú que esta es la página actual.)

Podría dividir el menú div de la página maestra en un marcador de posición de contenido, pero eso significaría que debo poner el menú en cada página .

¿Alguna idea, hay alguna buena solución para esto?

Respuesta

24

La manera más fácil es conseguir el controlador de corriente y la acción de RouteData del ViewContext. Tenga en cuenta el cambio en la firma y el uso de @ para escapar de la palabra clave.

<% var controller = ViewContext.RouteData.Values["controller"] as string ?? "Home"; 
    var action = ViewContext.RouteData.Values["action"] as string ?? "Index"; 
    var page = (controller + ":" + action).ToLower(); 
%> 

<%= Html.ActionLink("About", "About", "Home", null, 
        new { @class = page == "home:about" ? "current" : "") %> 
<%= Html.ActionLink("Home", "Index", "Home", null, 
        new { @class = page == "home:index" ? "current" : "") %> 

Tenga en cuenta que puede combinar esto con una extensión HtmlHelper como @ Jon's y hacerlo más limpio.

<%= Html.MenuLink("About", "About", "Home", null, null, "current") %> 

Dónde MenuActionLink es

public static class MenuHelperExtensions 
{ 
    public static string MenuLink(this HtmlHelper helper, 
            string text, 
            string action, 
            string controller, 
            object routeValues, 
            object htmlAttributes, 
            string currentClass) 
    { 
     RouteValueDictionary attributes = new RouteValueDictionary(htmlAttributes); 
     string currentController = helper.ViewContext.RouteData.Values["controller"] as string ?? "home"; 
     string currentAction = helper.ViewContext.RouteData.Values["action"] as string ?? "index"; 
     string page = string.Format("{0}:{1}", currentController, currentAction).ToLower(); 
     string thisPage = string.Format("{0}:{1}", controller, action).ToLower(); 
     attributes["class"] = (page == thisPage) ? currentClass : ""; 
     return helper.ActionLink(text, action, controller, new RouteValueDictionary(routeValues), attributes); 
    } 
} 
+0

No es una buena solución. Una vista no debe saber nada sobre controladores y acciones. Los datos a mostrar solo deben ser suministrados por el modelo. –

+1

Es solo un atajo para obtener la URL: podría hacer lo mismo con la URL solicitada, pero luego tendría que analizarla. Estoy satisfecho con este mecanismo que no rompe el patrón. – tvanfosson

+0

¿Es correcta la sintaxis? Me sale "No puedo aplicar la indexación con [] a una expresión de tipo 'System.Web.Routing.RouteData '" –

0

Puede ser que sea el quinto parámetro, por lo que coloca un nulo antes del atributo html. Este post aquí se describe como tal, aunque se puede pasar en algunas cosas en el cuarto argumento, el quinto es específicamente para htmlAttributes

+0

@class en lugar de clase :) –

1

Recientemente he creado un Auxiliar HTML de esta que parece:

public static string NavigationLink(this HtmlHelper helper, string path, string text) 
{ 
    string cssClass = String.Empty; 
    if (HttpContext.Current.Request.Path.IndexOf(path) != -1) 
    { 
     cssClass = "class = 'selected'"; 
    } 

    return String.Format(@"<li><a href='{0}' {1}>{2}</a></li>", path, cssClass, text); 
} 

la puesta en práctica se parece a esto:

<ul id="Navigation"> 
    <%=Html.NavigationLink("/Path1", "Text1")%> 
    <%=Html.NavigationLink("/Path2", "Text2")%> 
    <%=Html.NavigationLink("/Path3", "Text3")%> 
    <%=Html.NavigationLink("/Path4", "Text4")%> 
    </ul> 
+0

Tengo algunos problemas con esto. En primer lugar, no aborda la envoltura de cuerdas y se romperá si proporciona una carcasa diferente en la url (recuerde que los usuarios pueden escribirla directamente). En segundo lugar, será difícil probar la unidad dada la dependencia del HttpContext estático actual. En tercer lugar, se rompe si tiene múltiples niveles de acciones/menús ya que el nivel "superior" coincidirá con todos los subniveles. Por supuesto, mi solución también tiene el tercer problema, pero como no depende de la coincidencia de cadenas, es algo más fácil modificarla para acomodar múltiples niveles. – tvanfosson

+0

... Me gusta, y he tomado prestada la idea, gracias, la idea de convertirla en un método de extensión para hacer que el código de vista sea más ordenado. – tvanfosson

+0

¡Gracias por los comentarios! Todavía soy un novato en todo esto y siempre estoy buscando formas de mejorar mi código. – Jon

1

Si estás usando T4MVC , Puede utilizar esto:

 public static HtmlString MenuLink(
     this HtmlHelper helper, 
     string text, 
     IT4MVCActionResult action, 
     object htmlAttributes = null) 
    { 
     var currentController = helper.ViewContext.RouteData.Values["controller"] as string ?? "home"; 
     var currentAction = helper.ViewContext.RouteData.Values["action"] as string ?? "index"; 

     var attributes = new RouteValueDictionary(htmlAttributes); 
     var cssClass = (attributes.ContainsKey("class")) 
          ? attributes["class"] + " " 
          : string.Empty; 

     string selectedClass; 
     if(action.Controller.Equals(currentController, StringComparison.InvariantCultureIgnoreCase) 
     { 
      selectedClass = "selected-parent"; 
      if(action.Action.Equals(currentAction, StringComparison.InvariantCultureIgnoreCase)) 
       selectedClass = "selected"; 
     } 
     cssClass += selectedClass; 

     attributes["class"] = cssClass; 

     return helper.ActionLink(text, (ActionResult)action, attributes); 
    } 
0
<script type="javascript/text"> 
$(document).ready(function() { 

     @if (Request.Url.AbsolutePath.ToLower() == "/") 
     { 
      @Html.Raw("$('.navbar-nav li').eq(0).attr('class','active');") 
     } 

     @if (Request.Url.AbsolutePath.ToLower().Contains("details")) 
     { 
      @Html.Raw("$('.navbar-nav li').eq(1).attr('class','active');") 
     } 

     @if (Request.Url.AbsolutePath.ToLower().Contains("schedule")) 
     { 
      @Html.Raw("$('.navbar-nav li').eq(2).attr('class','active');") 
     } 

    }); 
</script> 

tiraron juntos en 5 minutos, probablemente podría refactorizar, pero debe darle la idea básica, es probablemente más útil para sitios más pequeños.

Cuestiones relacionadas