Come aggiungere la classe "attiva" a Html.ActionLink in ASP.NET MVC


128

Sto provando ad aggiungere una classe "attiva" alla mia barra di avvio bootstrap in MVC, ma quanto segue non mostra la classe attiva quando scritta in questo modo:

<ul class="nav navbar-nav">
  <li>@Html.ActionLink("Home", "Index", "Home", null, new {@class="active"})</li>
  <li>@Html.ActionLink("About", "About", "Home")</li>
  <li>@Html.ActionLink("Contact", "Contact", "Home")</li>
</ul>

Questo si risolve in quella che sembra una classe correttamente formattata, ma non funziona:

<a class="active" href="/">Home</a>

Nella documentazione Bootstrap afferma che i tag "a" non dovrebbero essere usati nella barra di navigazione, ma quanto sopra è come credo sia il modo corretto di aggiungere una classe a un Html.ActionLink. C'è un altro modo (ordinato) per farlo?


3
il codice che si risolve ha class = attivo in esso. Non è quello che dici di voler nella tua domanda? Come hai il tuo codice è come aggiungo le lezioni
Matt Bodily il

non sei troppo chiaro !!! Non capisco esattamente quale sia il problema aggiungendolo a Nav, anche se ho la sensazione, il modo in cui dovrebbe essere va bene
JC Lizard,

1
Qual è il problema con il codice risolto? Che cosa ti aspetti Puoi essere più specifico di "non sembra funzionare"? La tua domanda non è abbastanza chiara per aiutarti in questo momento.
dom

Modificato! scusate, quello che volevo dire era che la classe "attiva" non si mostra affatto
Gillespie,

2
Ho appena dato un'occhiata ai documenti di Bootstrap e penso che sia necessario aggiungere la activeclasse liall'elemento, non il a. Guarda il primo esempio qui: getbootstrap.com/components/#navbar
dom

Risposte:


300

In Bootstrap la activeclasse deve essere applicata <li>all'elemento e non a <a>. Guarda il primo esempio qui: http://getbootstrap.com/components/#navbar

Il modo in cui gestisci il tuo stile di interfaccia utente in base a ciò che è attivo o meno non ha nulla a che fare con l' ActionLinkhelper di ASP.NET MVC . Questa è la soluzione corretta per seguire come è stato creato il framework Bootstrap.

<ul class="nav navbar-nav">
    <li class="active">@Html.ActionLink("Home", "Index", "Home")</li>
    <li>@Html.ActionLink("About", "About", "Home")</li>
    <li>@Html.ActionLink("Contact", "Contact", "Home")</li>
</ul>

Modificare:

Poiché molto probabilmente riutilizzerai il tuo menu su più pagine, sarebbe intelligente avere un modo per applicare quella classe selezionata automaticamente in base alla pagina corrente piuttosto che copiare il menu più volte e farlo manualmente.

Il modo più semplice è semplicemente usare i valori contenuti in ViewContext.RouteData, vale a dire i valori Actione Controller. Potremmo basarci su ciò che hai attualmente con qualcosa del genere:

<ul class="nav navbar-nav">
    <li class="@(ViewContext.RouteData.Values["Action"].ToString() == "Index" ? "active" : "")">@Html.ActionLink("Home", "Index", "Home")</li>
    <li class="@(ViewContext.RouteData.Values["Action"].ToString() == "About" ? "active" : "")">@Html.ActionLink("About", "About", "Home")</li>
    <li class="@(ViewContext.RouteData.Values["Action"].ToString() == "Contact" ? "active" : "")">@Html.ActionLink("Contact", "Contact", "Home")</li>
</ul>

Non è abbastanza nel codice, ma eseguirà il lavoro e ti consentirà di estrarre il menu in una vista parziale, se lo desideri. Ci sono modi per farlo in un modo molto più pulito, ma da quando hai appena iniziato lo lascerò a quello. Buona fortuna per imparare ASP.NET MVC!


Modifica tardiva:

Questa domanda sembra ricevere un po 'di traffico, quindi ho pensato di aggiungere una soluzione più elegante usando HtmlHelperun'estensione.

Modifica 24-24-2015: ho dovuto riscrivere questo metodo per consentire più azioni e controller che attivano il comportamento selezionato, nonché la gestione per quando il metodo viene chiamato da una vista parziale dell'azione figlio, pensato di condividere l'aggiornamento!

public static string IsSelected(this HtmlHelper html, string controllers = "", string actions = "", string cssClass = "selected")
{
    ViewContext viewContext = html.ViewContext;
    bool isChildAction = viewContext.Controller.ControllerContext.IsChildAction;

    if (isChildAction)
        viewContext = html.ViewContext.ParentActionViewContext;

    RouteValueDictionary routeValues = viewContext.RouteData.Values;
    string currentAction = routeValues["action"].ToString();
    string currentController = routeValues["controller"].ToString();

    if (String.IsNullOrEmpty(actions))
        actions = currentAction;

    if (String.IsNullOrEmpty(controllers))
        controllers = currentController;

    string[] acceptedActions = actions.Trim().Split(',').Distinct().ToArray();
    string[] acceptedControllers = controllers.Trim().Split(',').Distinct().ToArray();

    return acceptedActions.Contains(currentAction) && acceptedControllers.Contains(currentController) ?
        cssClass : String.Empty;
}

Funziona con .NET Core:

public static string IsSelected(this IHtmlHelper htmlHelper, string controllers, string actions, string cssClass = "selected")
{
    string currentAction = htmlHelper.ViewContext.RouteData.Values["action"] as string;
    string currentController = htmlHelper.ViewContext.RouteData.Values["controller"] as string;

    IEnumerable<string> acceptedActions = (actions ?? currentAction).Split(',');
    IEnumerable<string> acceptedControllers = (controllers ?? currentController).Split(',');

    return acceptedActions.Contains(currentAction) && acceptedControllers.Contains(currentController) ?
        cssClass : String.Empty;
}

Esempio di utilizzo:

<ul>
    <li class="@Html.IsSelected(actions: "Home", controllers: "Default")">
        <a href="@Url.Action("Home", "Default")">Home</a>
    </li>
    <li class="@Html.IsSelected(actions: "List,Detail", controllers: "Default")">
        <a href="@Url.Action("List", "Default")">List</a>
    </li>
</ul>

Grazie, come ho già detto, è così che avevo originariamente, ma speravo di avere un metodo nel mio codice per cambiare la classe "attiva" tra gli oggetti selezionati.
Gillespie,

2
@Gillespie non preoccuparti! Ho modificato la mia risposta per aggiungere alcune informazioni che potrebbero aiutarti un po 'di più.
dom

5
Per quanto riguarda la prima modifica, in realtà ha funzionato solo per la pagina dell'indice. Sembra che il motivo fosse che durante il confronto non è riuscito in quanto ViewContext.RouteData.Values ​​["Azione"] non restituisce un oggetto di tipo String (ancora non so come ha funzionato per la prima pagina ....) . Quando ho cambiato tutto ViewContext.RouteData.Values ​​["Azione"] in ViewContext.RouteData.Values ​​["Azione"]. InString (), ha funzionato per tutte le pagine. Potrebbe voler aggiungere questo nella tua soluzione nel caso in cui qualcuno abbia lo stesso problema.
user3281466

2
@LonelyPixel forse questa risposta funziona per te?
dom

1
Per utenti VB.NET: <li class = "@ (If (ViewContext.RouteData.Values ​​(" Action "). ToString () =" Index "," active "," "))"> @ Html.ActionLink (" Home "," Index "," Home ") </li>
Andrea Antonangeli,

28

Estensione:

public static MvcHtmlString LiActionLink(this HtmlHelper html, string text, string action, string controller)
{
    var context = html.ViewContext;
    if (context.Controller.ControllerContext.IsChildAction)
        context = html.ViewContext.ParentActionViewContext;
    var routeValues = context.RouteData.Values;
    var currentAction = routeValues["action"].ToString();
    var currentController = routeValues["controller"].ToString();

    var str = String.Format("<li role=\"presentation\"{0}>{1}</li>",
        currentAction.Equals(action, StringComparison.InvariantCulture) &&
        currentController.Equals(controller, StringComparison.InvariantCulture) ?
        " class=\"active\"" :
        String.Empty, html.ActionLink(text, action, controller).ToHtmlString()
    );
    return new MvcHtmlString(str);
}

Uso:

<ul class="nav navbar-nav">
    @Html.LiActionLink("About", "About", "Home")
    @Html.LiActionLink("Contact", "Contact", "Home")
</ul>

1
Questa è un'estensione meravigliosamente efficiente. Funziona perfettamente ed è abbastanza elegante. Tanto di cappello, Prof! La mia unica lamentela è con role="presentation", che non è affatto appropriato per un menu di navigazione principale ( john.foliot.ca/aria-hidden/#pr ). Un elenco non ordinato è un contenitore appropriato per un insieme correlato di collegamenti, poiché li raggruppa in modo logico.
René Kåbis,

@ René Kåbis per la nausea del bootstrap getbootstrap.com/components/#nav-tabs
Prof

1
Questo non funziona quando l'utente inserisce manualmente l'URL in lettere minuscole o maiuscole, ad es. " domain.com/Login " e " domain.com/LOGIN ". Per la soluzione, var str = String.Format("<li role=\"presentation\"{0}>{1}</li>", currentAction.toLower().Equals(action.toLower(), StringComparison.InvariantCulture) && currentController.toLower().Equals(controller.toLower(), StringComparison.InvariantCulture) ? " class=\"active\"" : String.Empty, html.ActionLink(text, action, controller).ToHtmlString() );
sky91

20

Sono riuscito a farlo aggiungendo un parametro view bag in asp.net mvc. Ecco cosa ho fatto

Aggiunto ViewBag.Current = "Scheduler";parametro simile in ogni pagina

Nella pagina di layout

<ul class="nav navbar-nav">
     <li class="@(ViewBag.Current == "Scheduler" ? "active" : "") "><a href="@Url.Action("Index","Scheduler")" target="_self">Scheduler</a></li>
 </ul>

Questo ha risolto il mio problema.


Soluzione semplice e facile.
japes Sophey,

13

Potrebbe essere un po 'tardi. Ma spero che questo aiuti.

public static class Utilities
{
    public static string IsActive(this HtmlHelper html, 
                                  string control,
                                  string action)
    {
        var routeData = html.ViewContext.RouteData;

        var routeAction = (string)routeData.Values["action"];
        var routeControl = (string)routeData.Values["controller"];

        // both must match
        var returnActive = control == routeControl &&
                           action == routeAction;

        return returnActive ? "active" : "";
    }
}

E utilizzo come segue:

<div class="navbar-collapse collapse">
    <ul class="nav navbar-nav">
        <li class='@Html.IsActive("Home", "Index")'>
            @Html.ActionLink("Home", "Index", "Home")
        </li>
        <li class='@Html.IsActive("Home", "About")'>
            @Html.ActionLink("About", "About", "Home")
        </li>
        <li class='@Html.IsActive("Home", "Contact")'>
            @Html.ActionLink("Contact", "Contact", "Home")
        </li>
    </ul>
</div>

Ottenuto riferimento da http://www.codingeverything.com/2014/05/mvcbootstrapactivenavbar.html


1
Soluzione molto semplice ed elegante. Ho apportato alcuni miglioramenti qui gist.github.com/jean-rakotozafy/… per evidenziare un menu per tutte le azioni del controller.
Zan RAKOTO,

5

So che questa domanda è vecchia, ma mi piacerebbe solo aggiungere la mia voce qui. Credo che sia una buona idea lasciare la consapevolezza se un controller è attivo o meno al controller della vista.

Vorrei solo impostare un valore univoco per ciascuna vista nell'azione del controller. Ad esempio, se volessi rendere attivo il collegamento alla home page, farei qualcosa del genere:

public ActionResult Index()
{            
    ViewBag.Title = "Home";
    ViewBag.Home = "class = active";
    return View();
}

Quindi, a mio avviso, scriverò qualcosa del genere:

<li @ViewBag.Home>@Html.ActionLink("Home", "Index", "Home", null, new { title = "Go home" })</li>

Quando si passa a una pagina diversa, ad esempio Programmi, ViewBag.Home non esiste (invece ViewBag.Programs esiste); pertanto, non viene visualizzato nulla, nemmeno class = "". Penso che sia più pulito sia per la manutenibilità che per la pulizia. Tendo a voler sempre lasciare la logica fuori dalla vista il più possibile.


4

Considerando ciò che Damith ha pubblicato, mi piace pensare che tu possa semplicemente qualificarti attivo con Viewbag.Title (la migliore pratica è quella di popolare questo nelle tue pagine di contenuti permettendo alla tua _Layout.cshtmlpagina di contenere le barre dei link). Si noti inoltre che se si utilizzano voci di sottomenu funziona bene:

<li class="has-sub @(ViewBag.Title == "Dashboard 1" || ViewBag.Title == "Dashboard 2" ? "active" : "" )">
    <a href="javascript:;">
        <b class="caret"></b>
        <i class="fa fa-th-large"></i>
        <span>Dashboard</span>
    </a>
    <ul class="sub-menu">
        <li class="@(ViewBag.Title == "Dashboard 1" ? "active" : "")"><a href="index.html">Dashboard v1</a></li>
        <li class="@(ViewBag.Title == "Dashboard 2" ? "active" : "")"><a href="index_v2.html">Dashboard v2</a></li>
    </ul>
</li>

Pulito ed efficiente!
mggluscevic,

3

Ho modificato la risposta "non carina" di dom e l' ho resa più brutta. A volte due controller hanno i nomi delle azioni in conflitto (ovvero Index), quindi faccio questo:

<ul class="nav navbar-nav">
  <li class="@(ViewContext.RouteData.Values["Controller"].ToString() + ViewContext.RouteData.Values["Action"].ToString() == "HomeIndex" ? "active" : "")">@Html.ActionLink("Home", "Index", "Home")</li>
  <li class="@(ViewContext.RouteData.Values["Controller"].ToString() + ViewContext.RouteData.Values["Action"].ToString() == "AboutIndex" ? "active" : "")">@Html.ActionLink("About", "Index", "About")</li>
  <li class="@(ViewContext.RouteData.Values["Controller"].ToString() + ViewContext.RouteData.Values["Action"].ToString() == "ContactHome" ? "active" : "")">@Html.ActionLink("Contact", "Contact", "Home")</li>
</ul>

3

Puoi provare questo: nel mio caso sto caricando il menu dal database in base all'accesso basato sul ruolo, scrivi il codice su ogni vista su quale menu desideri attivare in base alla tua vista.

<script type="text/javascript">
        $(document).ready(function () {         
            $('li.active active-menu').removeClass('active active-menu');
            $('a[href="https://stackoverflow.com/MgtCustomer/Index"]').closest('li').addClass('active active-menu');
        });
</script>

3

Questa soluzione è semplice per Asp.net MCV 5.

  1. Creare una classe statica, ad esempio Utilitarios.cs.

  2. All'interno della classe creare un metodo statico:

    public static string IsLinkActive(this UrlHelper url, string action, string controller)
    {
        if (url.RequestContext.RouteData.Values["controller"].ToString() == controller &&
            url.RequestContext.RouteData.Values["action"].ToString() == action)
        {
            return "active";
        }
    
        return "";
    }
  3. chiama così

    <ul class="sidebar-menu" data-widget="tree">
        <li class="header">HEADER</li>
        <li class="@Url.IsLinkActive("Index", "Home")">
            <a href="@Url.Action("Index", "Home")"><i class="fa fa-link"></i> <span>Home</span></a>
        </li>
        <li class="@Url.IsLinkActive("About", "Home")">
            <a href="@Url.Action("About", "Home")"><i class="fa fa-link"></i><span>About</span></a>
        </li>
    </ul>

3

ASP.NET Core & Bootstrap 4

Risposta più aggiornata

Ho rielaborato la soluzione pulita di @crush per un modo aggiornato, compatibile ASP.NET Core e Bootstrap 4 per risolvere questo problema basato su un IHtmlHelpermetodo di estensione:

public static class LinkExtensions
{
    public static IHtmlContent ActiveActionLink(this IHtmlHelper html, string linkText, string actionName, string controllerName, object routeValues, object htmlAttributes)
    {
        return ActiveActionLink(html, linkText, actionName, controllerName, new RouteValueDictionary(routeValues), HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
    }

    public static IHtmlContent ActiveActionLink(this IHtmlHelper html, string linkText, string actionName, string controllerName, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes)
    {
        var routeData = html.ViewContext.RouteData;
        var routeAction = (string)routeData.Values["action"];
        var routeController = (string)routeData.Values["controller"];

        var active = controllerName.Equals(routeController) && actionName.Equals(routeAction);

        using (var writer = new StringWriter())
        {
            writer.WriteLine($"<li class='nav-item {(active ? "active" : "")}'>");
            html.ActionLink(linkText, actionName, controllerName, routeValues, htmlAttributes).WriteTo(writer, HtmlEncoder.Default);
            writer.WriteLine("</li>");
            return new HtmlString(writer.ToString());
        }
    }
}

uso

<nav class="navbar">
    <div class="collapse navbar-collapse">
        <ul class="navbar-nav">
            @Html.ActiveActionLink("Home", "Index", "Home", null, new { @class = "nav-link" })
            @Html.ActiveActionLink("About", "About", "Home", null, new { @class = "nav-link" })
            @Html.ActiveActionLink("Contact", "Contact", "TimeTracking", null, new { @class = "nav-link" })
        </ul>
    </div>
</nav>

1
Ottima soluzione Nel tuo esempio, come posso impostare 'Contatto' come attivo per impostazione predefinita?
Sig. Suman Kabir il

1
Grazie. La cosa buona è che non è necessario impostare un elemento attivo. Non appena viene visitata la pagina "Contatti", ActiveActionLink()verrà applicata la classe attiva a <li>:-)
WoIIe

dov'è la tua area di controllo?
Mohammad,

@Mohammad non capisco. Potresti per favore elaborare la tua domanda?
WoIIe

nella classe LinkExtensions non hai ottenuto l'area da routeData!
Mohammad il

3

Facile ASP.NET Core 3.0 e TagHelpers

[HtmlTargetElement("li", Attributes = "active-when")]
public class LiTagHelper : TagHelper
{
    public string ActiveWhen { get; set; }

    [ViewContext]
    [HtmlAttributeNotBound]
    public ViewContext ViewContextData { get; set; }

    public override void Process(TagHelperContext context, TagHelperOutput output)
    {
        if (ActiveWhen == null)
            return;

        var targetController = ActiveWhen.Split("/")[1];
        var targetAction = ActiveWhen.Split("/")[2];

        var currentController = ViewContextData.RouteData.Values["controller"].ToString();
        var currentAction = ViewContextData.RouteData.Values["action"].ToString();

        if (currentController.Equals(targetController) && currentAction.Equals(targetAction))
        {
            if (output.Attributes.ContainsName("class"))
            {
                output.Attributes.SetAttribute("class", $"{output.Attributes["class"].Value} active");
            }
            else
            {
                output.Attributes.SetAttribute("class", "active");
            }
        }
    }
}

Includi nel tuo _ViewImports.cs:

@addTagHelper *, YourAssemblyName

Uso:

 <li active-when="/Home/Index">

2

Aggiungi '.ToString' per migliorare il confronto su ASP.NET MVC

<ul class="nav navbar-nav">
<li class="@(ViewContext.RouteData.Values["Action"].ToString() == "Index" ? "active" : "")">@Html.ActionLink("Home", "Index", "Home")</li>
<li class="@(ViewContext.RouteData.Values["Action"].ToString() == "About" ? "active" : "")">@Html.ActionLink("About", "About", "Home")</li>
<li class="@(ViewContext.RouteData.Values["Action"].ToString() == "Contact" ? "active" : "")">@Html.ActionLink("Contact", "Contact", "Home")</li>

-


Questo non funzionerà se ci sono nomi di azioni uguali in due controller diversi. Provalo con i controller Home e About con l'azione Index.
hyde,

potresti trovare il server delle funzioni sul rasoio come: @functions { public bool IsActive(string action, string controller) { var actionRoute = ViewContext.RouteData.Values["Action"].ToString(); var controlRoute = ViewContext.RouteData.Values["Controller"].ToString(); return controller.Equals(controlRoute)&& actionRoute.Equals(actionRoute); } }e uso: <li class="@(IsActive("Index", "Home")? "active": "")">
Hua Trung

2

Possiamo anche creare UrlHelperda RequestContext che possiamo ottenere da MvcHandler stesso. Pertanto, credo che qualcuno che voglia mantenere questa logica nei modelli Razor in questo modo sarebbe utile:

  1. Nella radice del progetto creare una cartella denominata AppCode.
  2. Crea un file lì chiamato HtmlHelpers.cshtml
  3. Crea un aiuto lì dentro:

    @helper MenuItem(string action, string controller)
    {
         var mvcHandler = Context.CurrentHandler as MvcHandler;
         if (mvcHandler != null)
         {
             var url = new UrlHelper(mvcHandler.RequestContext);
             var routeData = mvcHandler.RequestContext.RouteData;
             var currentAction = routeData.Values["action"].ToString();
             var currentController = routeData.Values["controller"].ToString();
             var isCurrent = string.Equals(currentAction, action, StringComparison.InvariantCultureIgnoreCase) &&
                             string.Equals(currentController, controller, StringComparison.InvariantCultureIgnoreCase);
    
            <div class="@(isCurrent ? "active" : "")">
                <div>@url.Action(action, controller)</div>
            </div>
         }   
    }
  4. Quindi possiamo usare le nostre opinioni in questo modo:

    @HtmlHelpers.MenuItem("Default", "Home")

Spero che aiuti a qualcuno.


Questo è davvero fantastico. Ci sono degli svantaggi nelle prestazioni qui?
schiaccia il

@crush, non l'ho misurato, ma mi aspetto che abbia un basso impatto sulle prestazioni perché penso che il framework usi una logica simile per creare UrlHelperquello che hai Controller.Url. L'unica cosa è che probabilmente non vogliamo eseguire la creazione UrlHelperper ogni chiamata, MenuItemquindi possiamo applicare un segno di spunta per salvarlo negli elementi HttpContext dopo la prima chiamata all'helper, quindi lo facciamo solo una volta per richiesta.
Oleksii Aza,

2

è possibile con una funzione lambda

@{
string controllerAction = ViewContext.RouteData.Values["Controller"].ToString() + ViewContext.RouteData.Values["Action"].ToString();
    Func<string, string> IsSelected= x => x==controllerAction ? "active" : "";
}

quindi l'utilizzo

 @Html.ActionLink("Inicio", "Index", "Home", new { area = "" }, new { @class = IsSelected("HomeIndex")})

2

Ho creato HtmlHelperun'estensione che aggiunge un ActiveActionLinkmetodo per quelli di voi che vogliono aggiungere la classe "attiva" al collegamento stesso piuttosto che <li>circondare il collegamento.


public static class LinkExtensions
{
    public static MvcHtmlString ActiveActionLink(this HtmlHelper html, string linkText, string actionName, string controllerName, object routeValues, object htmlAttributes)
    {
        return ActiveActionLink(html, linkText, actionName, controllerName, new RouteValueDictionary(routeValues), HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
    }

    public static MvcHtmlString ActiveActionLink(this HtmlHelper html, string linkText, string actionName, string controllerName, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes)
    {
        const string activeClassName = "active";

        var routeData = html.ViewContext.RouteData;

        var routeAction = (string)routeData.Values["action"];
        var routeController = (string)routeData.Values["controller"];

        var active = controllerName.Equals(routeController) && actionName.Equals(routeAction);

        if (active)
        {
            var @class = (string)htmlAttributes["class"];

            htmlAttributes["class"] = string.IsNullOrEmpty(@class)
                ? activeClassName
                : @class + " active";
        }

        var link = html.ActionLink(linkText, actionName, controllerName, routeValues, htmlAttributes);

        return link;
    }
}

L'utilizzo è il seguente:

@Html.ActiveActionLink("Home", "Index", "Home", new { area = "" }, new { @class = "nav-item nav-link" })

1

la risposta di @dombenoit funziona. Anche se introduce del codice da mantenere. Controlla questa sintassi:

using (var nav = Html.Bootstrap().Begin(new Nav().Style(NavType.NavBar).SetLinksActiveByControllerAndAction()))
{
    @nav.ActionLink("Link 1", "action1")
    @nav.ActionLink("Link 2", "action2")
    @nav.Link("External Link", "#")
}

Si noti l'uso del .SetLinksActiveByControllerAndAction()metodo.

Se ti chiedi cosa rende possibile questa sintassi, dai un'occhiata a TwitterBootstrapMVC


Grazie per la risposta Dmitry, sto testando TwitterBootstrapMVC
Gillespie il

1

Stavo anche cercando una soluzione e jQuery mi ha aiutato molto. Innanzitutto, devi dare un "ID" ai tuoi <li>elementi.

<li id="listguides"><a href='/Guides/List'>List Guides</a></li>

Dopo averlo fatto nella pagina del layout, puoi dire a jQuery quale <li>elemento dovrebbe essere "selezionato" nella tua vista.

@section Scripts{
    <script type="text/javascript">
        $('#listguides').addClass('selected');
    </script>
}

Nota: è necessario averlo @RenderSection("scripts", required: false)nella pagina del layout, subito prima del </body>tag per aggiungere quella sezione.


1

Vorrei proporre questa soluzione che si basa sulla prima parte della risposta di Dom.

Definiamo innanzitutto due variabili, "azione" e "controller" e le usiamo per determinare il collegamento attivo:

{ string controller = ViewContext.RouteData.Values["Controller"].ToString();
string action = ViewContext.RouteData.Values["Action"].ToString();}

E poi:

<ul class="nav navbar-nav">
    <li class="@((controller == "Home" && action == "Index") ? "active" : "")">@Html.ActionLink("Home", "Index", "Home")</li>
    <li class="@((controller == "Home" && action == "About") ? "active" : "")">@Html.ActionLink("About", "About", "Home")</li>
    <li class="@((controller == "Home" && action == "Contact") ? "active" : "")">@Html.ActionLink("Contact", "Contact", "Home")</li>
</ul>

Ora sembra più bello e non c'è bisogno di soluzioni più complesse.


0

se non viene visualizzato affatto, il motivo è che sono necessari due segni @:

@@class

MA, credo che potresti dover avere la classe attiva sul tag "li" non sul tag "a". secondo anche i documenti bootstrap ( http://getbootstrap.com/components/#navbar-default ):

<ul class="nav navbar-nav">
  <li class="active"><a href="#">Home</a></li>
  <li><a href="#">Profile</a></li>
  <li><a href="#">Messages</a></li>
</ul>

pertanto il tuo codice sarà:

<ul class="nav navbar-nav">
  <li class="active">@Html.ActionLink("Home", "Index", "Home", null)</li>
  <li>@Html.ActionLink("About", "About", "Home")</li>
  <li>@Html.ActionLink("Contact", "Contact", "Home")</li>
</ul>

La classe @@ genera un errore, originariamente avevo il tuo esempio di codice sopra, che funziona, ma non è esattamente come Actionlink "dovrebbe" essere?
Gillespie,

modificato. @@ non è richiesto. devi mettere la classe su EA
JC Lizard il

0

Spero che questo aiuti, di seguito è come può essere il tuo menu:

 <ul class="nav navbar-nav">
   <li><a href="@Url.Action("Index", "Home")" class="@IsMenuSelected("Index","Home", "active")">Home</a></li>
   <li><a href="@Url.Action("About", "Home")" class="@IsMenuSelected("About", "Home", "active")">About</a></li>
   <li><a href="@Url.Action("Contact", "Home")" class="@IsMenuSelected("Contact", "Home", "active")">Contact</a></li>
 </ul>

E aggiungi sotto la funzione di supporto MVC sotto il tag html.

 @helper IsMenuSelected(string actionName, string controllerName, string className)
    {
            var conname = ViewContext.RouteData.Values["controller"].ToString().ToLower();
            var actname = ViewContext.RouteData.Values["action"].ToString().ToLower();

            if (conname == controllerName.ToLower() && actname == actionName.ToLower())
        {
            @className;
        }
    }

Ho indirizzato la risposta da http://questionbox.in/add-active-class-menu-link-html-actionlink-asp-net-mvc/


0

Mi sono reso conto che questo problema era un problema comune per alcuni di noi, quindi ho pubblicato la mia soluzione usando il pacchetto nuget. Di seguito puoi vedere come funziona. Spero che sarà utile.

Nota: questo pacchetto nuget è il mio primo pacchetto. Quindi, se vedi un errore, ti preghiamo di dare un feedback. Grazie.

  1. Installa il pacchetto o scarica il codice sorgente e aggiungi il tuo progetto

    -Install-Package Betalgo.MvcMenuNavigator
  2. Aggiungi le tue pagine a un enum

    public enum HeaderTop
    {
        Dashboard,
        Product
    }
    public enum HeaderSub
    {
        Index
    }
  3. Metti il ​​filtro in cima al tuo controller o azione

    [MenuNavigator(HeaderTop.Product, HeaderSub.Index)]
    public class ProductsController : Controller
    {
        public async Task<ActionResult> Index()
        {
            return View();
        }
    
        [MenuNavigator(HeaderTop.Dashboard, HeaderSub.Index)]
        public async Task<ActionResult> Dashboard()
        {
            return View();
        }
    }
  4. E usalo nel layout dell'intestazione in questo modo

    @{
    var headerTop = (HeaderTop?)MenuNavigatorPageDataNavigatorPageData.HeaderTop;
    var headerSub = (HeaderSub?)MenuNavigatorPageDataNavigatorPageData.HeaderSub;
    }
    <div class="nav-collapse collapse navbar-collapse navbar-responsive-collapse">
    <ul class="nav navbar-nav">
        <li class="@(headerTop==HeaderTop.Dashboard?"active selected open":"")">
            <a href="@Url.Action("Index","Home")">Dashboard</a>
        </li>
        <li class="@(headerTop==HeaderTop.Product?"active selected open":"")">
            <a href="@Url.Action("Index", "Products")">Products</a>
        </li>
    </ul>

Ulteriori informazioni: https://github.com/betalgo/MvcMenuNavigator


0

Credo che qui sia un codice più pulito e più piccolo per rendere il menu selezionato "attivo":

 <ul class="navbar-nav mr-auto">
                <li class="nav-item @Html.IfSelected("Index")">
                    <a class="nav-link" href="@Url.Action("Index", "Home")">Home</a>
                </li>
                <li class="nav-item @Html.IfSelected("Controls")">
                    <a class="nav-link" href="@Url.Action("Controls", "Home")">MVC Controls</a>
                </li>
                <li class="nav-item @Html.IfSelected("About")">
                    <a class="nav-link" href="@Url.Action("About", "Home")">About</a>
                </li>
</ul>

 public static string IfSelected(this HtmlHelper html, string action)
        {
            return html
                       .ViewContext
                       .RouteData
                       .Values["action"]
                       .ToString() == action
                            ? " active"
                            : "";
        }

Bello, anche se probabilmente deve essere esteso per controller e area in alcuni casi
planetClaire il

-1

Ho combinato le risposte sopra e ho creato la mia soluzione.

Così..

Per prima cosa nel blocco rasoio crea una variabile stringa che conterrà il valore del nome del controller e l'azione che viene chiamata dall'utente.

    @{
        string controllerAction =  ViewContext.RouteData.Values["Controller"].ToString() + ViewContext.RouteData.Values["Action"].ToString(); 
    }

Quindi utilizzare la combinazione di codice HTML e Razor:

    <ul class="nav navbar-nav">
        <li class="@(controllerAction == "HomeIndex" ? "active" : "" )">@Html.ActionLink("Home", "Index", "Home")</li>
        <li class="@(controllerAction == "AboutIndex" ? "active" : "" )">@Html.ActionLink("About", "Index", "About")</li>
        <li class="@(controllerAction == "HomeContact" ? "active" : "" )">@Html.ActionLink("Contact", "Contact", "Home")</li>
    </ul>

Penso che questo sia positivo perché non è necessario accedere a "ViewContext.RouteData.Values" ogni volta per ottenere il nome del controller e il nome dell'azione.


-1

La mia soluzione a questo problema è

<li class="@(Context.Request.Path.Value.ToLower().Contains("about") ? "active " : "" ) nav-item">
                <a class="nav-link" asp-area="" asp-controller="Home" asp-action="About">About</a>
            </li>

Un modo migliore potrebbe essere l'aggiunta di un metodo di estensione HTML per restituire il percorso corrente da confrontare con il collegamento


-1

L'ho fatto:

Crea un aiuto nella vista parziale del menu

 @helper RouterLink(string action, string controller)
{
    var IsActive = ViewContext.RouteData.Values["Controller"].ToString() == controller && ViewContext.RouteData.Values["Action"].ToString() == action;
    <text>href="@Url.Action(action, controller)"</text>if (IsActive){ <text>class="active"</text>}
}

Quindi l'ho usato nel tag anchor in questo modo:

<li><a @RouterLink("Index","Home")>Home</a></li>

La mia applicazione non aveva aree ma può anche essere inclusa come un'altra variabile nella funzione helper. A mio avviso, ho dovuto passare la classe attiva al tag anchor. Ma lipuò anche essere configurato in questo modo.


1
Vedete, il downvote non aiuta davvero se non menzionate il motivo.
Anup Sharma,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.