2009-06-03 10 views
13

einstellt Ich habe folgendes Menü in meiner Masterpage:ASP.NET MVC: Masterpage: Wie CSS-Klasse auf aktivem Menüpunkt

<ul id="menu" class="lavaLampBottomStyle"> 
    <li> 
     <%= Html.ActionLink("Employees", "Index", "Employees")%></li> 
    <li> 
     <%= Html.ActionLink("Customer", "Details", "Account")%></li> 
</ul> 

Ich brauche einen Weg, um die CSS-Klasse der aktuell aktiv li einzustellen zu "aktuell".

Mein erster Tipp es mit Hilfe von Javascript zu tun.

Ich würde so etwas in der Masterpage ist:

$("#menu li a").each(){ 
    if($(this).attr("href") == '<%= *GET CURRENT PAGE* %>'){ 
     $(this).parent("li").addClass("current"); 
    } 
    } 

Ist das ein guter Ansatz?

Wenn ja, wie bekomme ich den aktuellen URL-Teil wie im href?

Wenn nicht, was ist Ihr Vorschlag? :-)

FYI, die generierten HTML Ich bin nach:

<ul id="menu" class="lavaLampBottomStyle"> 
    <li> 
     <a href="/KszEmployees/Index">Employees</a></li> 
    <li> 
     <a class="current" href="/">Customer</a></li> 
</ul> 
+0

Wie sieht die letzte jQuery jeder Schleife aus? – Picflight

+0

Picflight ... und alle, die danach suchen, fügen Sie der Masterpage folgendes hinzu:

+0

vielen Dank für diese Frage :) haben das sehr ähnliche Problem, es hat sehr geholfen! –

Antwort

6

Das ist wahrscheinlich die am wenigsten intensive Art, es zu tun. Wenn Sie darauf zählen können, dass die Benutzer Javascript aktiviert haben, sehe ich nichts falsch daran und habe es gelegentlich selbst gemacht.

Request.Url ist das Objekt, an dem Sie interessiert sind, um die aktuelle Seite auf der Serverseite zu erhalten. Der Vorschlag, window.location.href von tvanfosson zu verwenden, ist auch nicht schlecht, wenn Sie es vollständig clientseitig behalten möchten.

Der Vorteil der Verwendung von serverseitig ist, dass Request.Url leicht zugängliche Teile der URL hat, wie Request.Url.Host, etc., um mit Ihren Link-Munging-Bedürfnissen zu helfen.

+0

nice edit. Ich werde das serverseitige Ding verwenden, da es wasserdichter aussieht als windows.location.href –

+0

Eigentlich hatte ich nicht daran gedacht, das Request-Objekt in der Rendering-Phase zu verwenden, da ich mit einem Plugin-Client arbeitete und nur aus dieser Perspektive darüber nachdachte . Ich muss sehen, ob das meinen Navigationscode sauberer macht. – tvanfosson

+0

Funktioniert mit: $ ("# Menü li a [href = <% = Request.Url.LocalPath%>]"). Parent ("li"). AddClass ("aktuell"); –

9

den aktuellen Standort aus window.location extrahieren. Verwenden Sie dann einen Selektor, der den Wert des href-Attributs angibt, um nur die übereinstimmenden Elemente auszuwählen (vermutlich nur eins).

var currentLocation = window.location.href; 
// probably needs to be massaged to extract just the path so that it works in dev/prod 

$("#menu li a[href$="+currentLocation+"]").addClass("current"); 
+0

Nicht in Betracht gezogen, es vollständig clientseitig zu halten. Keine schlechte Idee, window.location.href zu verwenden. –

+0

netter jquery Selektor, habe nicht daran gedacht :-) –

+0

Aber ich frage mich, ob das mit der "/" URL funktioniert .. –

-2

Dies sollte nicht mit Javascript durchgeführt werden! Die Entscheidung, auf welcher Seite Sie sich befinden, ist die Aufgabe des serverseitigen Codes. Es ist kein Verhalten der Benutzeroberfläche.

Lassen Sie das Menü als Benutzersteuerung und übergeben Sie einen Wert, um anzuzeigen, welcher Teil des Menüs hervorgehoben werden soll. Ich bin Front-End Person, kein .NET-Entwickler, aber so etwas wie dies:

<yourControl:menuControl runat="server" ID="menu" selectedPage="4" /> 
+1

Sie können Javascript & serverseitigen Code kombinieren .. Ich werde keine Kontrolle dafür machen. Außerdem ist es asp.net mvc. Und in Ihrer Lösung müssten Sie das Menü auf jeder Seite hinzufügen? + Es ist schwer, die Reihenfolge der Menüpunkte zu ändern. Viele Dinge sind falsch mit Ihrer Lösung. –

+3

+1 auf dies nicht mit JavaScript -1 für die Verwendung einer Kontrolle –

+0

Ich weiß nicht. Ich denke, es ist eine triviale Sache zu scheitern, wenn JS deaktiviert ist. Sie verlieren im Wesentlichen eine Gedächtnishilfe, wenn sie fehlschlägt. Sie brechen die Funktionalität nicht. –

15

Wenn Sie wollen es alle Server-Seite zu tun, ich diese vorher getan haben. Erstellen Sie eine Aktion Filterattribut:

public class PageOptionsAttribute : ActionFilterAttribute 
{ 
    public string Title { get; set; } 
    public string Section { get; set; } 

    public override void OnActionExecuting(ActionExecutingContext filterContext) 
    { 
     var controller = filterContext.Controller as ControllerBase; 
     if (controller != null) 
     { 
      controller.SetPageSection(this.Section); 
      controller.SetPageTitle(this.Title); 
     } 

     base.OnActionExecuting(filterContext); 
    } 
} 

Dies erfordert zwei Methoden in meiner Controller Klasse, die alle meine Controller erben von:

public class ControllerBase : Controller 
{ 
    public void SetPageSection(string section) 
    { 
        // use the section defined or the controller name if none 
     ViewData["PageSection"] = section != null ? 
         section : this.RouteData.Values["controller"].ToString(); 
    } 

    public void SetPageTitle(string title) 
    { 
     ViewData["PageTitle"] = title; 
    } 
} 

Stellen Sie den Titel und Seitenbereich auf Sie Controller-Methoden:

public class HomeController : ControllerBase 
{ 
    [PageOptions(Title="Home Page", Section="Home")] 
    public ActionResult Index() 
    { } 
} 

Dann rufe ich den ViewData-Wert von meiner Masterseite (dies wird ViewData nicht stören.Modell):

<body class="<%=ViewData["PageSection"] %>"> 

dann per CSS zu verweisen, statt .Current aufrufen, geben Sie jedem nav Element eine ID und verwenden Sie dann den Körper Klasse in Kombination mit dieser ID der aktuellen Seite zu bestimmen.

body.home #HomeNav { /* selected */ } 
body.about #AboutNav { /* selected */ } 
+0

Wenn all Ihr ViewModel von einem Basis-ViewModel erbt, können Sie alternativ die Title/Section-Props in Ihrem Basisansichtsmodell hinzufügen und sie beim Auffüllen in Ihren View-Methoden festlegen. Die obige Methode geht davon aus, dass jede Controller-Methode jedes Mal die gleiche Ansicht zurückgibt (oder ähnliche Ansichten, die eine Titel-/Abschnittsdefinition teilen), was nicht immer zutrifft. –

+0

scheint ziemlich komplex .. Ich mag das :-) Ich werde diese Methode für zukünftige Projekte studieren, aber aus Zeitmangel werde ich die Javascript-Lösung verwenden, die ich bereits für jetzt implementiert habe .. Danke für die Mühe, viel appriciated. –

+0

Dies wird viel weniger trivial, wenn Ihre Menüs dynamisch generiert werden, wie zum Beispiel ein CMS. Aus diesem Blickwinkel beantwortete ich die Frage von. Wenn Sie feste Verbindungen haben, dann ist Ihre Lösung am besten. –

0

Ich hatte das gleiche Problem. Mit den folgenden Antworten habe ich die folgende Lösung zusammengestellt.

https://stackoverflow.com/a/4733394/280972

https://stackoverflow.com/a/5650735/280972

In HtmlHelpers.cs:

public static class HtmlHelpers 
{ 
    public static HtmlString MenuLink(
     this HtmlHelper htmlHelper, 
     string linkText, 
     string actionName, 
     string controllerName 
    ) 
    { 
     var currentAction = htmlHelper.ViewContext.RouteData.GetRequiredString("action"); 
     var currentController = htmlHelper.ViewContext.RouteData.GetRequiredString("controller"); 
     var link = htmlHelper.ActionLink(linkText, actionName, controllerName); 
     var prefix = (actionName == currentAction && controllerName == currentController) ? String.Format("<li class=\"current\">") : String.Format("<li>"); 
     const string suffix = "</li>"; 
     return new HtmlString(prefix + link + suffix); 
    } 
} 

Im Layout:

<ul class="nav nav-list"> 
    <li class="nav-header">Statistics</li> 
    @Html.MenuLink("Number of logins", "Logins", "Statistics") 
</ul> 

Beachten Sie, dass die MenuLink-Helfer schaffen sowohl den li-Tag und das a-tag.

Feedback zu dieser Lösung ist sehr willkommen!