using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.AspNetCore.Razor.TagHelpers; using System; namespace AcdiuTools.TagHelpers { /// /// 自动为当前激活的导航链接添加 'active' 类和 'aria-current="page"' 属性。 /// /// 用法示例: /// <a asp-active-link="true" asp-controller="Home" asp-action="Index" class="nav-link">首页</a> /// /// [HtmlTargetElement("a", Attributes = "asp-active-link")] public class ActiveLinkTagHelper : TagHelper { /// /// 获取或设置当前视图的上下文,用于读取路由数据。 /// [ViewContext] [HtmlAttributeNotBound] public ViewContext ViewContext { get; set; } = default!; /// /// 是否启用自动激活检测。对应 HTML 属性: asp-active-link /// [HtmlAttributeName("asp-active-link")] public bool IsActiveLink { get; set; } /// /// 目标控制器名称。映射自内置的 asp-controller 属性。 /// [HtmlAttributeName("asp-controller")] public string? Controller { get; set; } /// /// 目标 Action 名称。映射自内置的 asp-action 属性。 /// [HtmlAttributeName("asp-action")] public string? Action { get; set; } /// /// 执行 TagHelper 逻辑。 /// /// TagHelper 上下文。 /// TagHelper 输出内容。 public override void Process(TagHelperContext context, TagHelperOutput output) { // 如果未设置 asp-active-link="true",则不执行逻辑 if (!IsActiveLink) return; // 1. 获取当前路由中的 Controller 和 Action var routeData = ViewContext.RouteData.Values; string? currentController = routeData["controller"]?.ToString(); string? currentAction = routeData["action"]?.ToString(); // 2. 确定目标 Controller 和 Action (如果未指定,则默认为当前页面或 Index) string targetController = Controller ?? currentController ?? string.Empty; string targetAction = Action ?? "Index"; // 3. 忽略大小写进行匹配 bool isActive = string.Equals(currentController, targetController, StringComparison.OrdinalIgnoreCase) && string.Equals(currentAction, targetAction, StringComparison.OrdinalIgnoreCase); if (isActive) { // 4. 合并 Class 属性,确保不覆盖原有样式 var existingClasses = output.Attributes["class"]?.Value?.ToString(); if (string.IsNullOrWhiteSpace(existingClasses)) { output.Attributes.SetAttribute("class", "active"); } else if (!existingClasses.Contains("active")) { output.Attributes.SetAttribute("class", $"{existingClasses} active"); } // 5. 增强无障碍支持 output.Attributes.SetAttribute("aria-current", "page"); } } } }