ASP.NET MVC:主页面:如何在活动菜单项上设置css类

13

我在我的母版页中有以下菜单:

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

我需要一种方法将当前活动的li元素的CSS类设置为"current"。

我的第一个猜测是使用JavaScript来实现。

我会在主页面中包含如下内容:

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

这是一个好方法吗?

如果是的话,我该如何获取当前URL部分,就像在href中一样?

如果不是的话,你有什么建议?:-)

顺便说一句,我想要生成的HTML是:

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

最终的jQuery each循环是什么样子的? - Picflight
将以下内容添加到主页面,以便于Picflight和其他人查找:<script type="text/javascript"> $(function(){ /** 根据路径自动选择和突出显示菜单 **/ $("#menu li a[href=<%=Request.Url.LocalPath %>]").parent("li").addClass("selected"); }); </script> - Charlie Brown
非常感谢您提出这个问题 :) 我有一个非常类似的问题,这对我帮助很大! - Alexander Beletsky
5个回答

15

如果您希望全部在服务器端执行,我以前做过这个。创建一个操作筛选器属性:

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

这里调用了我的ControllerBase类中的两个方法,所有我的控制器都继承自该类:

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

在您的控制器方法中设置标题和页面部分:

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

然后我从我的母版页调用ViewData值(这不会影响ViewData.Model):

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

使用CSS进行引用时,不要调用.current,而是给每个导航项分配一个ID,然后与body类一起使用该ID来确定当前页面。

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

看起来相当复杂..我喜欢这个 :-) 我会在将来的项目中研究这种方法,但由于时间不足,现在我会使用我已经实现的JavaScript解决方案..感谢您的努力,非常感激。 - Thomas Stock
如果您的菜单是动态生成的,比如说一个CMS,那么这就变得不那么简单了。这是我回答问题的角度。如果您有硬链接,那么是的,您的解决方案是最好的。 - Chad Ruppert
然后,您需要添加一个 if 语句块,以在页面段值与 li 元素匹配时添加属性。 - John Sheehan
这样做的另一个好处是,您将拥有一个有限的章节列表可包含在您的CSS中,但如果您匹配URL,则可以评估无限数量的URL。 - John Sheehan
我在PHP中使用相同的方法,现在我也可以在.NET中做到。谢谢。 - guzart
显示剩余3条评论

9
从 window.location 中提取当前位置。然后使用指定 href 属性值的选择器来选择匹配的元素(可能只有一个)。
 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");

是的 - 我所说的“按摩”URL就是这个意思,也就是说,如果整个URL只有/结尾,那么它只能以/结尾。我在工作中有一些类似于使用手风琴插件导航过滤器的代码,但今天我生病在家。 :-( - tvanfosson
请注意,您还需要删除协议、端口和服务器名称。 - tvanfosson
我将使用Chad的服务器端组件,结合你的jQuery。 - Thomas Stock
2
它可以与以下内容一起使用: $("#menu li a[href=<%=Request.Url.LocalPath %>]").parent("li").addClass("current"); - Thomas Stock
但可能会使用全服务器端的解决方案.. 我会尝试那个,然后再看看我接受谁 :-) - Thomas Stock
显示剩余3条评论

6
这可能是最不费力的方法。如果您可以确信用户启用了JavaScript,那么我认为这样做没有任何问题,并且我自己有时也这样做。
Request.Url是您感兴趣的对象,以获取服务器端的当前页面。tvanfosson建议使用window.location.href,如果您希望完全基于客户端进行操作,则这种建议也不错。
使用服务器端的优点是,Request.Url具有易于访问的URL部分,例如Request.Url.Host等,可帮助您管理链接。

不错的编辑。我会使用服务器端的东西,因为它看起来比windows.location.href更可靠。 - Thomas Stock
事实上,在渲染阶段我没有考虑使用请求对象,因为我一直在客户端使用插件,并且只从那个角度考虑它。我将不得不看看这是否可以使我的导航代码更清晰。 - tvanfosson
使用以下代码:$("#menu li a[href=<%=Request.Url.LocalPath %>]").parent("li").addClass("current"); - Thomas Stock

0

我曾经遇到过同样的问题。通过以下答案,我成功地组合出了下面的解决方案。

https://dev59.com/Km445IYBdhLWcg3wucio#4733394

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

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

在布局中:

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

请注意,MenuLink-helper会创建li标签和a标签。
非常欢迎对此解决方案提供反馈!

-2
这个操作不应该使用Javascript完成!决定用户所在的页面是服务器端代码的职责,而不是UI行为。
将菜单作为用户控件,并传递一个值以指示应突出显示菜单的哪个部分。我是前端开发人员,而不是.NET开发人员,但像这样的方法可能会有所帮助:
<yourControl:menuControl runat="server" ID="menu" selectedPage="4" />

1
你可以结合JavaScript和服务器端代码。我不会为此制作控件。此外,这是ASP.NET MVC。在你的解决方案中,你必须在每个页面上包含菜单吗?另外,改变菜单项的顺序很困难。你的解决方案有很多问题。 - Thomas Stock
我不知道。如果JS被禁用,我认为它是一个微不足道的失败。如果它失败了,你基本上失去了一种记忆辅助工具。但你并没有破坏功能。 - Chad Ruppert
我的.NET实现还可以,但我毫不怀疑它可以做得更好。我猜我应该坚持认为Javascript是一个糟糕的解决方案。@Chad,网站可用性的下降并不是微不足道的,导航对用户来说非常重要,如果用户已经着陆在该页面上,那么内存与此无关。这个问题的Javascript解决方案会导致页面膨胀——没有充分的理由说明这个逻辑不应该在服务器上执行,这样可以更快、更可靠地完成。 - edeverett
@edeverett,除了简单的菜单活动状态,您并没有使用面包屑或其他辅助功能吗?我希望这不是您唯一的可用性提示。 - Chad Ruppert

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