活动菜单项 - ASP.NET MVC3主页

65

我一直在寻找一个适当的解决方案,为了给主页面上的菜单项分配“活动/当前”类。对于这个问题,有关是在客户端还是服务器端进行处理的观点存在分歧。

实际上,我对JavaScript和MVC都很陌生,所以我没有意见。我希望用最“清晰”和最合适的方式来解决这个问题。

我有以下jQuery代码来分配“活动”类到<li>项……唯一的问题是“索引”或默认视图菜单项将总是被分配活动类,因为URL总是其他菜单链接的子字符串:

(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
   }
});
有更好的方法吗?能否帮忙让客户端版本做到无懈可击?使得“index”或默认链接始终处于“活动”状态?是否可以给索引方法分配一个虚拟扩展名?例如,不仅仅是基本 URL,而是 localhost/home/dashboard,这样它就不会成为每个链接的子字符串了?说实话,我并不真正理解服务器端的方法,这就是为什么我试图在客户端使用 jQuery 来完成…感谢任何帮助。
5个回答

113

一个自定义的HTML帮助程序通常可以很好地完成工作:

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

并且在您的母版页中:

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

现在只需要定义 .current 的 CSS 类即可。


27
值得注意的是,htmlHelper.ActionLink() 需要添加 "using System.Web.Mvc.Html;" 命名空间。 - 4imble
5
如果您在MVC3中使用Razor,您还需要在视图中导入命名空间。您可以通过在视图中添加@using <NAMESPACE>来实现。 - Duncan
1
我在这方面遇到了一个问题。如果在“link2”页面中,我有一个指向“link3”的链接,它指向另一个控制器和操作,但它是“link2”部分的一部分。由于请求中的控制器和操作与我们传递给助手的不匹配,“link2”不再作为控制器和操作处于活动状态。我已经想出了一个干净的解决方案:没有会话,在视图中没有丑陋的代码。http://arturito.net/2011/08/03/asp-net-mvc-2-highlight-selected-menu-item-on-the-site-master-without-session/额外的部分是具有路由映射的字典。 - Artur Kedzior
2
除了答案之外,以下链接也很有用:http://msdn.microsoft.com/en-us/vs2010trainingcourse_aspnetmvc3formsandvalidation_topic3.aspx - mg1075
1
@gardarvalur,您可以像处理其他参数一样从RouteData中检索它们:RouteData.Value["foobar"] - Darin Dimitrov
显示剩余5条评论

5

增加了区域支持:

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

4

以下是我对这个问题的解决方案。

我创建了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";
    }

然后我有我的菜单块。它长这样:
<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>

我的方法根据Home控制器的当前操作,为每个div返回类名。 你可以深入研究,并向该方法添加一个参数,该参数指定控制器的名称,以避免出现具有相同名称但属于不同控制器的操作时出现问题。


2

-1
我通常做的是给body标签分配一个基于路径部分的类。所以,如果你在路径上进行String.Replace操作,将/blogs/posts/1转换为class="blogs posts 1"。
然后,您可以分配CSS规则来处理它。例如,如果您有一个名为“blogs”的菜单项,您可以只需执行如下规则:
BODY.blogs li.blogs { /* your style */}

或者,如果您想要特定的样式,如果您在帖子页面上,只需反之,如果您在博客根页面上

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

2
不太喜欢这个解决方案...每个菜单项都需要创建一个类,是吧? - Michael

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接