ASP.NET Core 2中如何判断当前菜单并动态设置激活状态
嘿,这个问题我在ASP.NET Core 2的项目里折腾过好几次,给你分享几个实用的解决办法,帮你搞定导航栏的激活状态:
方法1:直接利用ViewContext获取当前路由(最省心的基础方案)
这个方法不需要额外写复杂代码,直接通过ViewContext拿到当前请求的控制器和动作名称,然后对比判断即可。
首先在你的_NavBar.cshtml分部视图里,先获取当前路由信息:
@{ // 从路由数据里提取当前控制器和动作,为空时设为空字符串避免报错 var currentController = ViewContext.RouteData.Values["Controller"]?.ToString() ?? ""; var currentAction = ViewContext.RouteData.Values["Action"]?.ToString() ?? ""; }
然后在导航项里添加判断逻辑,动态设置active类:
<ul class="nav navbar-nav"> <li class="@(currentController.Equals("Home", StringComparison.OrdinalIgnoreCase) && currentAction.Equals("Index", StringComparison.OrdinalIgnoreCase) ? "active" : "")"> <a asp-controller="Home" asp-action="Index">首页</a> </li> <li class="@(currentController.Equals("About", StringComparison.OrdinalIgnoreCase) && currentAction.Equals("Index", StringComparison.OrdinalIgnoreCase) ? "active" : "")"> <a asp-controller="About" asp-action="Index">关于页</a> </li> <li class="@(currentController.Equals("Contact", StringComparison.OrdinalIgnoreCase) && currentAction.Equals("Index", StringComparison.OrdinalIgnoreCase) ? "active" : "")"> <a asp-controller="Contact" asp-action="Index">联系页</a> </li> </ul>
这里用OrdinalIgnoreCase是为了避免大小写敏感的问题,比如控制器名称如果是home也能匹配上。
方法2:自定义Tag Helper(更优雅的可复用方案)
如果觉得每个导航项都写三元运算符太啰嗦,可以自定义一个Tag Helper来简化代码,以后新增导航项也更方便。
步骤1:创建ActiveTagHelper类
在项目里新建一个类(比如放在TagHelpers文件夹下):
using Microsoft.AspNetCore.Razor.TagHelpers; using Microsoft.AspNetCore.Http; [HtmlTargetElement("li", Attributes = "asp-active-controller, asp-active-action")] public class ActiveTagHelper : TagHelper { private readonly IHttpContextAccessor _httpContextAccessor; // 通过依赖注入获取HttpContextAccessor public ActiveTagHelper(IHttpContextAccessor httpContextAccessor) { _httpContextAccessor = httpContextAccessor; } // 接收传入的控制器名称 [HtmlAttributeName("asp-active-controller")] public string TargetController { get; set; } // 接收传入的动作名称 [HtmlAttributeName("asp-active-action")] public string TargetAction { get; set; } public override void Process(TagHelperContext context, TagHelperOutput output) { var currentRoute = _httpContextAccessor.HttpContext.Request.RouteValues; var currentController = currentRoute["Controller"]?.ToString() ?? ""; var currentAction = currentRoute["Action"]?.ToString() ?? ""; // 对比当前路由和目标路由,匹配的话添加active类 if (currentController.Equals(TargetController, StringComparison.OrdinalIgnoreCase) && currentAction.Equals(TargetAction, StringComparison.OrdinalIgnoreCase)) { var existingClass = output.Attributes["class"]?.Value.ToString() ?? ""; output.Attributes.SetAttribute("class", $"{existingClass} active".Trim()); } base.Process(context, output); } }
步骤2:注册Tag Helper
在_ViewImports.cshtml里添加注册代码,把你的项目命名空间替换进去:
@addTagHelper *, YourProjectNameSpace
步骤3:在_NavBar里使用
现在导航项的代码就简洁多了:
<ul class="nav navbar-nav"> <li asp-active-controller="Home" asp-active-action="Index"> <a asp-controller="Home" asp-action="Index">首页</a> </li> <li asp-active-controller="About" asp-active-action="Index"> <a asp-controller="About" asp-action="Index">关于页</a> </li> <li asp-active-controller="Contact" asp-active-action="Index"> <a asp-controller="Contact" asp-action="Index">联系页</a> </li> </ul>
方法3:用ViewBag传递激活状态(适合小型项目)
如果你的项目页面很少,也可以在每个控制器的Action里手动设置ViewBag,然后在分部视图里判断:
比如在HomeController的Index方法里:
public IActionResult Index() { ViewBag.ActiveMenu = "Home"; return View(); }
AboutController的Index方法:
public IActionResult Index() { ViewBag.ActiveMenu = "About"; return View(); }
然后_NavBar.cshtml里:
<ul class="nav navbar-nav"> <li class="@(ViewBag.ActiveMenu == "Home" ? "active" : "")"> <a asp-controller="Home" asp-action="Index">首页</a> </li> <li class="@(ViewBag.ActiveMenu == "About" ? "active" : "")"> <a asp-controller="About" asp-action="Index">关于页</a> </li> <li class="@(ViewBag.ActiveMenu == "Contact" ? "active" : "")"> <a asp-controller="Contact" asp-action="Index">联系页</a> </li> </ul>
这个方法简单,但缺点是每个Action都要写一遍,不够灵活,适合页面不多的小型项目。
内容的提问来源于stack exchange,提问作者user9248102
相关产品推荐
相关产品推荐

