Cách thêm lớp Active active vào Html.ActionLink trong ASP.NET MVC


128

Tôi đang cố gắng thêm một lớp "hoạt động" vào thanh điều hướng bootstrap của mình trong MVC, nhưng sau đây không hiển thị lớp hoạt động khi được viết như thế này:

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

Điều này giải quyết những gì trông giống như một lớp được định dạng chính xác, nhưng không hoạt động:

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

Trong tài liệu Bootstrap, nó nói rằng các thẻ 'a' không nên được sử dụng trong thanh điều hướng, nhưng trên đây là cách tôi tin là cách chính xác để thêm một lớp vào Html.ActionLink. Có cách nào khác (gọn gàng) tôi có thể làm điều này không?


3
mã giải quyết có class = active trong đó. Đó không phải là những gì bạn nói bạn muốn trong câu hỏi của bạn? Cách bạn có mã của mình là cách tôi thêm các lớp
Matt Bodily 5/12/13

bạn không quá rõ ràng !!! Tôi không hiểu chính xác vấn đề gì khi thêm nó vào điều hướng, mặc dù tôi có cảm giác, cách nó sẽ ổn thôi
JC Lizard

1
Có vấn đề gì với mã được giải quyết? Bạn đang mong đợi điều gì? Bạn có thể cụ thể hơn "dường như không hoạt động"? Câu hỏi của bạn không đủ rõ ràng để giúp bạn ngay bây giờ.
dom

Đã chỉnh sửa! xin lỗi, điều tôi muốn nói là lớp "hoạt động" hoàn toàn không hiển thị
Gillespie

2
Chỉ cần liếc qua các tài liệu của Bootstrap và tôi nghĩ bạn cần thêm activelớp vào thành liphần chứ không phải a. Xem ví dụ đầu tiên tại đây: getbootstrap.com/components/#navbar
dom

Câu trả lời:


300

Trong Bootstrap, activelớp cần được áp dụng cho <li>phần tử chứ không phải <a>. Xem ví dụ đầu tiên tại đây: http://getbootstrap.com/components/#navbar

Cách bạn xử lý kiểu UI của bạn dựa trên những gì đang hoạt động hay không liên quan đến trình ActionLinktrợ giúp của ASP.NET MVC . Đây là giải pháp thích hợp để làm theo cách xây dựng khung 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>

Biên tập:

Vì rất có thể bạn sẽ sử dụng lại menu của mình trên nhiều trang, nên sẽ rất thông minh khi áp dụng lớp đã chọn đó tự động dựa trên trang hiện tại thay vì sao chép menu nhiều lần và thực hiện thủ công.

Cách dễ nhất là chỉ cần sử dụng các giá trị có trong ViewContext.RouteData, cụ thể là ActionControllercác giá trị. Chúng tôi có thể xây dựng dựa trên những gì bạn hiện có với thứ như thế này:

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

Nó không đẹp về mã, nhưng nó sẽ hoàn thành công việc và cho phép bạn trích xuất menu của mình thành một phần xem nếu bạn muốn. Có nhiều cách để làm điều này theo cách sạch sẽ hơn nhiều, nhưng vì bạn mới bắt đầu nên tôi sẽ để nó ở đó. Tốt nhất của may mắn học ASP.NET MVC!


Chỉnh sửa muộn:

Câu hỏi này dường như nhận được một chút lưu lượng truy cập vì vậy tôi nghĩ rằng tôi sẽ đưa ra một giải pháp thanh lịch hơn bằng cách sử dụng HtmlHelpertiện ích mở rộng.

Chỉnh sửa 03-24-2015: Phải viết lại phương thức này để cho phép nhiều hành động và bộ điều khiển kích hoạt hành vi đã chọn, cũng như xử lý khi phương thức được gọi từ chế độ xem một phần hành động con, nghĩ rằng tôi sẽ chia sẻ bản cập nhật!

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

Hoạt động với .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;
}

Sử dụng mẫu:

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

Cảm ơn, như tôi đã đề cập, đây là cách tôi có nó ban đầu, nhưng tôi đã hy vọng có một phương thức trong toàn bộ mã thay đổi lớp "hoạt động" giữa các đối tượng được chọn.
Gillespie

2
@Gillespie không phải lo lắng! Tôi đã chỉnh sửa câu trả lời của mình để thêm một số thông tin có thể giúp bạn thêm một chút.
dom

5
Liên quan đến lần chỉnh sửa đầu tiên, nó thực sự chỉ hoạt động cho trang Index. Có vẻ lý do là khi thực hiện so sánh, nó đã thất bại vì ViewContext.RouteData.Values ​​["Action"] không trả về một đối tượng kiểu String (vẫn không biết nó hoạt động như thế nào cho trang đầu tiên ....) . Khi tôi thay đổi tất cả ViewContext.RouteData.Values ​​["Action"] thành ViewContext.RouteData.Values ​​["Action"]. ToString (), nó hoạt động cho tất cả các trang. Có thể muốn thêm điều này trong giải pháp của bạn chỉ trong trường hợp ai đó gặp vấn đề tương tự.
dùng3281466

2
@LonelyPixel có lẽ câu trả lời này phù hợp với bạn?
dom

1
Đối với người dùng VB.NET: <li class = "@ (If (ViewContext.RouteData.Values ​​(" Action "). ToString () =" Index "," active "," "))"> @ Html.ActionLink (" Trang chủ "," Chỉ mục "," Trang chủ ") </ li>
Andrea Antonangeli

28

Sự mở rộng:

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

Sử dụng:

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

1
Đây là một phần mở rộng hiệu quả đẹp. Hoạt động hoàn hảo và khá thanh lịch. Ngả mũ chào bạn, Giáo sư! Sự kìm kẹp duy nhất của tôi là với role="presentation", điều này hoàn toàn không thích hợp cho một menu điều hướng chính ( john.foliot.ca/aria-hidden/#pr ). Một danh sách không có thứ tự là rất nhiều một thùng chứa thích hợp cho một tập hợp các liên kết, vì nó nhóm chúng lại với nhau một cách hợp lý.
René Kåbis

@ René Kåbis nó cho bootstrap naulation getbootstrap.com/components/#nav-tabs
Giáo sư

1
Điều này không hoạt động khi người dùng nhập url thủ công bằng chữ in thường hoặc chữ in hoa, vd. " domain.com/Login " và " domain.com/LOGIN ". Đối với giải pháp, 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

Tôi đã thực hiện điều này bằng cách thêm một tham số túi xem trong asp.net mvc. Tôi đã làm gì ở đây

Đã thêm ViewBag.Current = "Scheduler";tham số như trong mỗi trang

Trong trang bố trí

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

Điều này đã giải quyết vấn đề của tôi.


Giải pháp đơn giản và dễ dàng.
japes Sophey

13

Có thể muộn một chút. Nhưng hy vọng điều này sẽ giúp.

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

Và cách sử dụng như sau:

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

Có tài liệu tham khảo từ http://www.codingeverything.com/2014/05/mvcbootstrapactivenavbar.html


1
Giải pháp rất đơn giản và thanh lịch. Tôi đã thực hiện một số cải tiến ở đây gist.github.com/jean-rakotozafy/ từ để làm nổi bật một menu cho tất cả các hành động của bộ điều khiển.
Zan RAKOTO

5

Tôi biết câu hỏi này đã cũ, nhưng tôi sẽ chỉ muốn thêm giọng nói của mình ở đây. Tôi tin rằng nên để lại kiến ​​thức về việc một liên kết có hoạt động với bộ điều khiển của chế độ xem hay không.

Tôi sẽ chỉ đặt một giá trị duy nhất cho mỗi chế độ xem trong hành động của bộ điều khiển. Ví dụ, nếu tôi muốn làm cho liên kết trang chủ hoạt động, tôi sẽ làm một cái gì đó như thế này:

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

Sau đó, theo quan điểm của tôi, tôi sẽ viết một cái gì đó như thế này:

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

Khi bạn điều hướng đến một trang khác, giả sử Chương trình, ViewBag.Home không tồn tại (thay vào đó là ViewBag.Programs); do đó, không có gì được hiển thị, thậm chí cả class = "". Tôi nghĩ rằng điều này là sạch hơn cả về khả năng bảo trì và sạch sẽ. Tôi có xu hướng luôn muốn để logic ra khỏi tầm nhìn nhiều nhất có thể.


4

Xem xét những gì Damith đã đăng, tôi muốn nghĩ rằng bạn chỉ có thể đủ điều kiện hoạt động bởi Viewbag.Title (cách tốt nhất là đưa thông tin này vào các trang nội dung cho phép _Layout.cshtmltrang của bạn giữ các thanh liên kết của bạn). Cũng lưu ý rằng nếu bạn đang sử dụng các mục menu phụ, nó cũng hoạt động tốt:

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

Sạch sẽ và hiệu quả!
mggluscevic

3

Tôi đã sửa đổi câu trả lời "không đẹp" của dom và làm cho nó xấu hơn. Đôi khi hai bộ điều khiển có tên hành động xung đột (ví dụ Index) vì vậy tôi làm điều này:

<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

Bạn có thể thử điều này: Trong trường hợp của tôi, tôi đang tải menu từ cơ sở dữ liệu dựa trên quyền truy cập dựa trên vai trò, Viết mã trên mỗi chế độ xem mà bạn muốn kích hoạt dựa trên chế độ xem của bạn.

<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

Giải pháp này đơn giản cho Asp.net MCV 5.

  1. Tạo một lớp tĩnh, ví dụ Utilitarios.cs.

  2. Bên trong Class tạo một phương thức tĩnh:

    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. gọi như thế này

    <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

Câu trả lời cập nhật nhất

Tôi đã làm việc lại giải pháp gọn gàng của @crush cho một cách tương thích , cập nhật ASP.NET CoreBootstrap 4 để giải quyết vấn đề này dựa trên IHtmlHelperphương pháp mở rộng:

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

Sử dụng

<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
Giải pháp rất tốt. Trong ví dụ của bạn, làm cách nào tôi có thể đặt 'Liên hệ' là hoạt động theo mặc định?
Md. Suman Kabir

1
Cảm ơn bạn. Điều tốt là bạn không cần thiết lập một yếu tố hoạt động. Ngay khi trang 'Liên hệ' được truy cập, ActiveActionLink()sẽ áp dụng lớp hoạt động cho <li>:-)
WoIIe

bạn đang kiểm tra khu vực ở đâu?
Mohammad

@Mohammad Tôi không hiểu. Bạn có thể vui lòng giải thích câu hỏi của bạn?
WoIIe

trong lớp LinkExtensions bạn đã không nhận được khu vực từ routeData!
Mohammad

3

Dễ dàng ASP.NET Core 3.0 và 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");
            }
        }
    }
}

Bao gồm trong _ViewImports.cs của bạn:

@addTagHelper *, YourAssemblyName

Sử dụng:

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

2

Thêm '.ToString' để cải thiện so sánh trên 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>

-


Điều này sẽ không hoạt động nếu có cùng tên hành động trong hai bộ điều khiển khác nhau. Kiểm tra nó với bộ điều khiển Home và About với hành động Index.
hyde

Bạn có thể hủy cài đặt máy chủ chức năng trên dao cạo như: @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); } }và cách sử dụng: <li class="@(IsActive("Index", "Home")? "active": "")">
Hua Trung

2

Chúng tôi cũng có thể tạo UrlHelpertừ RequestContext mà chúng tôi có thể nhận được từ chính MvcHandler. Do đó, tôi tin tưởng vào một người muốn giữ logic này trong các mẫu Dao cạo theo cách sau sẽ hữu ích:

  1. Trong dự án root tạo một thư mục có tên AppCode.
  2. Tạo một tập tin có tên HtmlHelpers.cshtml
  3. Tạo một người trợ giúp trong đó:

    @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. Sau đó, chúng tôi có thể sử dụng trên quan điểm của chúng tôi như thế này:

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

Hy vọng rằng nó sẽ giúp cho một ai đó.


Điều này thực sự mát mẻ. Có bất kỳ nhược điểm hiệu suất ở đây?
nghiền nát

@crush, tôi chưa đo được, nhưng tôi hy vọng nó có tác động hiệu suất thấp vì tôi nghĩ khung này sử dụng logic tương tự để tạo ra UrlHelperthứ bạn có Controller.Url. Điều duy nhất là có lẽ chúng tôi không muốn thực hiện việc tạo UrlHelpercho mỗi cuộc gọi để MenuItemchúng tôi có thể áp dụng lưu dấu vào lưu các mục httpContext sau lần gọi đầu tiên tới người trợ giúp để chúng tôi chỉ thực hiện một lần cho mỗi yêu cầu.
Oleksii Aza

2

có thể với hàm lambda

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

sau đó sử dụng

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

2

Tôi đã tạo một HtmlHelpertiện ích mở rộng bổ sung một ActiveActionLinkphương thức cho những bạn muốn thêm lớp "hoạt động" vào chính liên kết chứ không phải là <li>liên kết xung quanh.


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

Cách sử dụng như sau:

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

1

câu trả lời của @dombenoit hoạt động. Mặc dù nó giới thiệu một số mã để duy trì. Kiểm tra cú pháp này:

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", "#")
}

Chú ý sử dụng .SetLinksActiveByControllerAndAction()phương pháp.

Nếu bạn tự hỏi điều gì làm cho cú pháp này có thể, hãy xem TwitterBootstrapMVC


Cảm ơn câu trả lời của Dmitry, tôi đang thử nghiệm TwitterBootstrapMVC
Gillespie

1

Tôi cũng đang tìm kiếm một giải pháp và jQuery đã giúp đỡ khá nhiều. Trước tiên, bạn cần cung cấp 'id cho các <li>yếu tố của bạn .

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

Sau khi thực hiện điều này trong trang bố cục của bạn, bạn có thể cho jQuery biết <li>phần tử nào sẽ được 'chọn' trong chế độ xem của bạn.

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

Lưu ý: Bạn cần phải có @RenderSection("scripts", required: false)trong trang bố trí của mình, ngay trước </body>thẻ để thêm phần đó.


1

Tôi muốn đề xuất giải pháp này dựa trên phần đầu tiên của câu trả lời của Dom.

Trước tiên chúng tôi xác định hai biến, "hành động" và "bộ điều khiển" và sử dụng chúng để xác định liên kết hoạt động:

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

Và sau đó:

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

Bây giờ nó trông đẹp hơn và không cần các giải pháp phức tạp hơn.


0

nếu nó hoàn toàn không hiển thị, lý do là bạn cần hai dấu @:

@@class

NHƯNG, tôi tin rằng bạn có thể cần phải có lớp hoạt động trên thẻ "li" chứ không phải trên thẻ "a". theo tài liệu bootstrap quá ( 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>

do đó mã của bạn sẽ là:

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

Lớp @@ đưa ra một lỗi, ban đầu tôi có ví dụ mã của bạn ở trên, hoạt động, nhưng không chính xác như Actionlinks "nên" là gì?
Xe tăng

chỉnh sửa. @@ không bắt buộc. bạn phải đưa lớp học lên EA
JC Lizard

0

Hy vọng điều này sẽ giúp, dưới đây là cách thực đơn của bạn có thể:

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

Và thêm chức năng trợ giúp MVC bên dưới thẻ 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;
        }
    }

Tôi đã giới thiệu câu trả lời từ http://questionbox.in/add-active- class- menu- link-html-actionlink-asp-net-mvc/


0

Tôi nhận ra rằng vấn đề này là một vấn đề phổ biến đối với một số người trong chúng tôi, vì vậy tôi đã xuất bản giải pháp của riêng mình bằng gói nuget. Dưới đây bạn có thể thấy nó hoạt động như thế nào. Tôi hy vọng điều đó sẽ hữu ích.

Lưu ý: Gói nuget này là gói đầu tiên của tôi. Vì vậy, nếu bạn thấy một sai lầm, xin vui lòng cung cấp thông tin phản hồi. Cảm ơn bạn.

  1. Cài đặt Gói hoặc tải xuống mã nguồn và thêm Dự án của bạn

    -Install-Package Betalgo.MvcMenuNavigator
  2. Thêm trang của bạn vào enum

    public enum HeaderTop
    {
        Dashboard,
        Product
    }
    public enum HeaderSub
    {
        Index
    }
  3. Đặt Bộ lọc lên trên Bộ điều khiển hoặc Hành động của bạn

    [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. Và sử dụng nó trong bố cục tiêu đề của bạn như thế này

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

Thông tin thêm: https://github.com/betalgo/MvcMothyNavigator


0

Tôi tin rằng đây là một mã sạch hơn và nhỏ hơn để làm cho menu được chọn là "hoạt động":

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

Đẹp, mặc dù có lẽ cần phải được mở rộng cho bộ điều khiển & khu vực trong một số trường hợp
tinhClaire

-1

Tôi đã kết hợp các câu trả lời ở trên và đưa ra giải pháp của mình.

Vì thế..

Đầu tiên trong khối dao cạo tạo một biến chuỗi sẽ chứa giá trị tên của bộ điều khiển và hành động được gọi bởi người dùng.

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

Sau đó, sử dụng kết hợp mã HTML và Dao cạo:

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

Tôi nghĩ rằng điều này tốt bởi vì bạn không cần phải truy cập "ViewContext.RouteData.Values" mỗi lần để có được tên bộ điều khiển và tên hành động.


-1

Giải pháp của tôi cho vấn đề này là

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

Một cách tốt hơn có thể là thêm một phương thức mở rộng Html để trả về đường dẫn hiện tại được so sánh với liên kết


-1

Tôi đã làm điều này:

Tạo một người trợ giúp trong menu xem một phần

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

Sau đó, sử dụng nó trong thẻ neo như thế này:

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

Ứng dụng của tôi không có khu vực nhưng nó cũng có thể được đưa vào như một biến khác trong hàm trợ giúp. Và tôi đã phải chuyển lớp hoạt động sang thẻ neo theo quan điểm của mình. Nhưng licũng có thể được cấu hình như thế này.


1
Bạn thấy đấy, downvote không thực sự giúp ích nếu bạn không đề cập đến lý do.
Anup Sharma
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.