asp.net-mvc 将“活动”标签添加到 asp.net mvc 母版页中的导航列表

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/214583/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-07 22:47:54  来源:igfitidea点击:

Adding "active" tag to navigation list in an asp.net mvc master page

asp.net-mvc

提问by dp.

In the default asp.net mvc project, in the Site.Master file, there is a menu navigation list:

在默认的asp.net mvc项目中,在Site.Master文件中,有一个菜单导航列表:

<div id="menucontainer">
    <ul id="menu">              
        <li><%= Html.ActionLink("Home", "Index", "Home")%></li>
        <li><%= Html.ActionLink("About Us", "About", "Home")%></li>
    </ul>
</div>

This renders in the browser to:

这在浏览器中呈现为:

<div id="menucontainer"> 
    <ul id="menu">              
        <li><a href="/">Home</a></li> 
        <li><a href="/Home/About">About Us</a></li> 
    </ul> 
</div> 

I want to be able to dynamically set the active list item, based on the view that is being called. That is, when the user is looking at the home page, I would want the following HTML to be created:

我希望能够根据正在调用的视图动态设置活动列表项。也就是说,当用户查看主页时,我希望创建以下 HTML:

<div id="menucontainer"> 
    <ul id="menu">              
        <li class="active"><a href="/">Home</a></li> 
        <li><a href="/Home/About">About Us</a></li> 
    </ul> 
</div> 

I would expect that the way to do this would be something like:

我希望这样做的方法是这样的:

<div id="menucontainer">
    <ul id="menu">              
        <li <% if(actionName == "Index"){%> class="active"<%}%>><%= Html.ActionLink("Home", "Index", "Home")%></li>
        <li <% if(actionName == "About"){%> class="active"<%}%>><%= Html.ActionLink("About Us", "About", "Home")%></li>
    </ul>
</div>

The key bit here is the <% if(actionName == "Index"){%> class="active"<%}%>line. I do not know how to determine what the current actionName is.

这里的关键是<% if(actionName == "Index"){%> class="active"<%}%>线。我不知道如何确定当前的 actionName 是什么。

Any suggestions on how to do this? Or, if I'm on completely the wrong track, is there a better way to do this?

关于如何做到这一点的任何建议?或者,如果我完全走错了路,有没有更好的方法来做到这一点?

回答by Adam Carr

I made myself a helper method to handle this type of thing. In the code behind of my master page (could be pushed of to an extension method ... probably a better approach), I put the following code.

我给自己做了一个辅助方法来处理这种类型的事情。在我的母版页后面的代码中(可以推送到扩展方法......可能是更好的方法),我放置了以下代码。

protected string ActiveActionLinkHelper(string linkText, string actionName, string controlName, string activeClassName)
{
    if (ViewContext.RouteData.Values["action"].ToString() == actionName && 
            ViewContext.RouteData.Values["controller"].ToString() == controlName)
        return Html.ActionLink(linkText, actionName, controlName, new { Class = activeClassName });

    return Html.ActionLink(linkText, actionName, controlName);
}

Then, I just call it in my page like so:

然后,我只是在我的页面中调用它,如下所示:

<%= ActiveActionLinkHelper("Home", "Index", "Home", "selected")%>

回答by Craig Stuntz

Inside a view, you can get the current action name with:

在视图中,您可以通过以下方式获取当前操作名称:

ViewContext.RouteData.Values["action"].ToString()

回答by labilbe

You can also try to detect which is the current selected tab from its controller name and view name, then add the class attribute.

您也可以尝试从其控制器名称和视图名称中检测当前选择的选项卡,然后添加类属性。

public static string MenuActionLink(this HtmlHelper helper, string linkText, string actionName, string controllerName)
{
    var htmlAttributes = new RouteValueDictionary();

    if (helper.ViewContext.Controller.GetType().Name.Equals(controllerName + "Controller", StringComparison.OrdinalIgnoreCase))
    {
        htmlAttributes.Add("class", "current");
    }

    return helper.ActionLink(linkText, actionName, controllerName, new RouteValueDictionary(), htmlAttributes);
}

回答by Telvin Nguyen

In MVC 3 Razor View Engine, you can do it as:

在 MVC 3 Razor View Engine 中,您可以这样做:

@{string ctrName = ViewContext.RouteData.Values["controller"].ToString();}

<div id="menucontainer">
  <ul id="menu"> 
    <li @if(ctrName == "Home"){<text> class="active"</text>}>@ Html.ActionLink("Home",  "Index", "Home")</li>
    <li @if(ctrName == "About"){<text> class="active"</text>}>@ Html.ActionLink("About Us", "About", "Home")</li>
  </ul>
</div>

My sample worked when I have two pages as: Home/About and its controller has same name Index, so I get controller Name for distinction insteed of action. If you want to get action, just replace with following:

当我有两个页面时,我的示例工作:Home/About 并且它的控制器具有相同的名称索引,所以我得到控制器名称以区分动作。如果您想采取行动,只需替换为以下内容:

@{string ctrName = ViewContext.RouteData.Values["action"].ToString();}

回答by Nanan

An old question but hopefully someone might find this very helpful.

一个老问题,但希望有人可能会觉得这很有帮助。

  1. Put some thing that you can use to identify your page in the ViewBag, I used ViewgBag.PageName
  1. ViewBag 中放置一些您可以用来识别您的页面的东西,我使用了ViewgBag.PageName

For example, in index.cshtml, put something like

例如,在index.cshtml 中,放置类似

@{
    ViewBag.PageName = "Index";
}
  1. Add a class to each link item with a conditional statement to return activeif the page being visited has the required value, or return an empty string otherwise. View below for details:
  1. 使用条件语句向每个链接项添加一个类,如果正在访问的页面具有所需的值,则返回活动,否则返回空字符串。查看下面的详细信息:

<li class="@((ViewBag.PageName == "Index") ? "active" : "")"><a href="@Url.Action("Index","Home")">Home</a></li>
<li class="@((ViewBag.PageName == "About") ? "active" : "")"><a href="@Url.Action("About","Home")">About</a></li>
<li class="@((ViewBag.PageName == "Contact") ? "active" : "")"><a href="@Url.Action("Contact","Home")">Contact</a></li>

I didn't just test it, I use this method in my projects

我不只是测试它,我在我的项目中使用这种方法

回答by Tim Iles

To contribute my own answer (tested in MVC4), I took a few best bits of the other answers, fixed a few issues, and added a helper to work with urls that aren't necessarily resolved via Controller & Action (eg. if you have an embedded CMS dealing with some page links, etc.)

为了贡献我自己的答案(在 MVC4 中测试),我采用了其他答案的一些最佳部分,修复了一些问题,并添加了一个助手来处理不一定通过控制器和操作解决的网址(例如,如果您有一个嵌入式 CMS 处理一些页面链接等)

The code is also forkable on github: https://gist.github.com/2851684

代码也可以在github上分叉:https://gist.github.com/2851684

/// 
/// adds the active class if the link's action & controller matches current request
/// 
public static MvcHtmlString MenuActionLink(this HtmlHelper htmlHelper,
    string linkText, string actionName, string controllerName,
    object routeValues = null, object htmlAttributes = null,
    string activeClassName = "active")
{
    IDictionary htmlAttributesDictionary =
        HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);

    if (((string)htmlHelper.ViewContext.RouteData.Values["controller"])
            .Equals(controllerName, StringComparison.OrdinalIgnoreCase) &&
        ((string)htmlHelper.ViewContext.RouteData.Values["action"])
            .Equals(actionName, StringComparison.OrdinalIgnoreCase))
    {
        // careful in case class already exists
        htmlAttributesDictionary["class"] += " " + activeClassName;
    }

    return htmlHelper.ActionLink(linkText, actionName, controllerName,
                                    new RouteValueDictionary(routeValues),
                                    htmlAttributesDictionary);
}

/// 
/// adds the active class if the link's path matches current request
/// 
public static MvcHtmlString MenuActionLink(this HtmlHelper htmlHelper,
    string linkText, string path, object htmlAttributes = null,
    string activeClassName = "active")
{
    IDictionary htmlAttributesDictionary =
        HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
    if (HttpContext.Current.Request.Path
        .Equals(path, StringComparison.OrdinalIgnoreCase))
    {
        // careful in case class already exists
        htmlAttributesDictionary["class"] += " " + activeClassName;
    }
    var tagBuilder = new TagBuilder("a")
                            {
                                InnerHtml = !string.IsNullOrEmpty(linkText)
                                                ? HttpUtility.HtmlEncode(linkText)
                                                : string.Empty
                            };
    tagBuilder.MergeAttributes(htmlAttributesDictionary);
    tagBuilder.MergeAttribute("href", path);
    return MvcHtmlString.Create(tagBuilder.ToString(TagRenderMode.Normal));
}

回答by Anytoe

Using MVC3 with a Razor View offers another option:

将 MVC3 与 Razor 视图一起使用提供了另一种选择:

_Layout.cshtml:

_Layout.cshtml:

<li class="@ViewBag.NavClassHome">@Html.ActionLink("Home", "Index", "Home")</li>
<li class="@ViewBag.NavClassAbout">@Html.ActionLink("Disclaimer", "About", "Home")</li>

HomeController:

家庭控制器:

public ActionResult Index() {
    ViewBag.NavClassHome = "active";
    return View();
} 

public ActionResult About() {
    ViewBag.NavClassAbout = "active";
    return View();
}

If you want to preserve this for a postback as well, you have to assign the ViewBag value here as well:

如果您还想为回发保留它,您还必须在此处分配 ViewBag 值:

[HttpPost]
public ActionResult Index() {
    ViewBag.NavClassHome = "active";
    return View();
}

[HttpPost]
public ActionResult About() {
    ViewBag.NavClassAbout = "active";
    return View();
}

Tested and working fine for me, but you will have a css class name in your server side code.

经过测试并且对我来说工作正常,但是您的服务器端代码中将有一个 css 类名。

回答by Bermy Dev

I wanted to have a bit more control over my layout, and this is what I did.

我想对我的布局有更多的控制,这就是我所做的。

Create a LayoutModel that other models inherit:

创建一个其他模型继承的 LayoutModel:

public abstract class LayoutModel
{
    public CurrentPage CurrentPage { get; set; }
}

Create a LayoutAttribute that inherits from ActionFilterAttribute like so:

创建一个继承自 ActionFilterAttribute 的 LayoutAttribute,如下所示:

public class LayoutAttribute : ActionFilterAttribute
{
    private CurrentPage _currentPage { get; set; }

    public LayoutAttribute(
        CurrentPage CurrentPage
    ){
        _currentPage = CurrentPage;
    }

    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        var result = filterContext.Result as ViewResultBase;
        if (result == null || result.Model == null || !(result.Model is LayoutModel)) return;

        ((LayoutModel)result.Model).CurrentPage = _currentPage;
    }
}

Now on the Action or Controller level I can set the current page (and other stuff if I wanted) like this:

现在在 Action 或 Controller 级别,我可以像这样设置当前页面(以及其他我想要的内容):

[Layout(CurrentPage.Account)]
public class MyController : Controller
{

}

In my layout view I now have access to the current page, and whatever else I add to the LayoutModel.

在我的布局视图中,我现在可以访问当前页面,以及我添加到 LayoutModel 的任何其他内容。

回答by Slee

This should work using jQuery on the client side of things, uses Google to serve the latest jQuery library:

这应该在客户端使用 jQuery 工作,使用 Google 来提供最新的 jQuery 库:

<script src="http://www.google.com/jsapi" type="text/javascript" language="javascript"></script>
<script type="text/javascript" language="javascript">google.load("jquery", "1");</script>  

<script language="javascript" type="text/javascript">
      $(document).ready(function(){
          var str=location.href.toLowerCase(); 
        $('#menucontainer ul#menu li a').each(function() {
                if (str.indexOf(this.href.toLowerCase()) > -1) {
                        $(this).attr("class","current"); //hightlight parent tab
                     }  
                });
      });  
    </script>

回答by Ricardo Vera

Using MVC3 with a Razor View, you can implement this like:

使用带有 Razor 视图的 MVC3,您可以像这样实现:

<ul id="menu">
 @if (ViewContext.RouteData.Values["action"].ToString() == "Index")
 {
 <li class="active">@Html.ActionLink("Home", "Index", "Home")</li>
 }
 else
 {
 <li>@Html.ActionLink("Home", "Index", "Home")</li>
 }
 @if (ViewContext.RouteData.Values["action"].ToString() == "About")
 {
 <li class="active">@Html.ActionLink("About", "About", "Home")</li>
 }
 else
 {
 <li>@Html.ActionLink("About", "About", "Home")</li>
 }
</ul>

And then applying your style of your ".active" class like:

然后应用你的“.active”类的风格,如:

ul#menu li.active 
{
 text-decoration:underline;
}