2011-01-18 12 views
64

Ho cercato di trovare una soluzione appropriata per assegnare la classe "attivo/corrente" alle voci di menu dalla pagina principale. La linea è divisa in due per quanto riguarda il lato client o server.voce di menu attiva - pagina master di asp.net mvc3

Sinceramente sono nuovo su JavaScript e MVC quindi non ho un'opinione. Preferirei farlo nel modo "più pulito" e più appropriato.

Ho il seguente codice jQuery per assegnare la classe "attiva" all'elemento <li> ... l'unico problema è l'"indice" o la voce di menu di visualizzazione predefinita verrà sempre assegnata alla classe attiva, perché l'URL è sempre una sottostringa degli altri collegamenti del menu:

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

C'è un modo migliore per farlo, ragazzi? Qualcuno potrebbe almeno aiutarmi a ottenere la versione lato client a prova di proiettile? In modo che l'"indice" o il collegamento predefinito sia sempre "attivo"? C'è un modo per assegnare un'estensione contraffatta al metodo dell'indice? come invece del solo URL di base sarebbe localhost/home/dashboard in modo che non fosse una sottostringa di ogni link?

Sinceramente, in realtà non seguo i metodi di questo server-side, motivo per cui sto cercando di farlo lato client con jQuery ... qualsiasi aiuto sarebbe apprezzato.

risposta

114

Un aiuto HTML personalizzato di solito fa il lavoro bene:

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

e nella tua pagina master:

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

Ora tutto ciò che rimane è definire la classe CSS .current.

+27

Vale la pena notare htmlHelper.ActionLink() ha bisogno di "using System.Web.Mvc.Html;" – 4imble

+1

Funziona brillantemente +1 – 4imble

+5

Devi anche importare lo spazio dei nomi nella tua vista, se usi Razor in MVC3 puoi farlo aggiungendo @using alla tua vista – Duncan

-1

Quello che faccio di solito è assegnare una classe al tag body che si basa sulle parti del percorso. Quindi, se esegui un String.Replace sul percorso per trasformare/blogs/posts/1 in class = "blog posts 1".

Quindi, è possibile assegnare le regole CSS per gestirlo. Ad esempio, se si dispone di una voce di menu per "blog", si può solo fare una regola come

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

o se si desidera uno stile particolare se la vostra su un post unico vizio, se siete sulla radice blog pagina

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

non pazzi per questa soluzione ... richiede la creazione di una classe per ogni singola voce di menu, non è vero? – Michael

4

Ecco la mia soluzione di questo problema.

ho creato seguente metodo di estensione della classe HtmlHelpers:

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

Poi ho il mio menublock. Assomiglia a questo:

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

Quindi il mio metodo restituisce il nome della classe a ogni div in base all'azione corrente del controller Home. Puoi approfondire e aggiungere al metodo un parametro, che specifica il nome del controller per evitare problemi, quando hai azioni con lo stesso nome ma di controller diversi.

5

Aggiunto il supporto per le aree:

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

Attraverso JQuery u può fare in questo modo:

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

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

Problemi correlati