在ASP.NET MVC 6项目中,我有以下内容:
[Route("help/how-it-works")]
public IActionResult HowItWorks() {
return View();
}
我想创建一个标签助手,如下所示:
<a class="menu" asp-controller="Help" asp-action="HowItWorks" route-is="help/how-it-works" css-class="active">How it works</a>
所以route-is标签帮助器将检查当前路由是否是&#34; help / how-it-works&#34; ...如果是,那么添加&#34;活跃&#34;到A标签的css类。
所以我开始创建一个标签助手:
[TargetElement("a", Attributes = "route-is, css-class")]
public class RouteTagHelper : TagHelper
{
public override void Process(TagHelperContext context, TagHelperOutput output)
{
String routeIs = context.AllAttributes["route-is"].ToString();
String cssClass = context.AllAttributes["css-class"].ToString();
if (String.IsNullOrWhiteSpace(cssClass))
cssClass = "active";
ViewContext.RouteData.Values.Keys;
}
}// Process
我的问题是如何确定当前的路线是&#34;帮助/如何运作&#34;如果是将Css类添加到A标记而不更改任何其他内容。
有没有人知道如何做到这一点?
更新1
使用属性路由时解决了重复值的问题,并添加了Daniel J.G提出的替代方法。
[TargetElement("a", Attributes = RouteIsName)]
[TargetElement("a", Attributes = RouteHasName)]
public class ActiveRouteTagHelper : TagHelper
{
private const String RouteIsName = "route-is";
private const String RouteHasName = "route-has";
private const String RouteCssName = "route-css";
private IActionContextAccessor _actionContextAccessor;
private IUrlHelper _urlHelper;
[HtmlAttributeName(RouteCssName)]
public String RouteCss { get; set; } = "active";
[HtmlAttributeName(RouteHasName)]
public String RouteHas { get; set; }
[HtmlAttributeName(RouteIsName)]
public String RouteIs { get; set; }
public ActiveRouteTagHelper(IActionContextAccessor actionContextAccessor, IUrlHelper urlHelper)
{
_actionContextAccessor = actionContextAccessor;
_urlHelper = urlHelper;
} // ActiveRouteTagHelper
public override void Process(TagHelperContext context, TagHelperOutput output)
{
IDictionary<String, Object> values = _actionContextAccessor.ActionContext.RouteData.Values;
String route = _urlHelper.RouteUrl(values.Distinct()).ToLowerInvariant();
Boolean match = false;
if (!String.IsNullOrWhiteSpace(RouteIs))
{
match = route == RouteIs;
} else {
if (RouteHas != null) {
String[] keys = RouteHas.Split(',');
if (keys.Length > 0)
match = keys.All(x => route.Contains(x.ToLowerInvariant()));
}
}
if (match)
{
TagBuilder link = new TagBuilder("a");
link.AddCssClass(RouteCss);
output.MergeAttributes(link);
}
} // Process
} // ActiveRouteTagHelper
答案 0 :(得分:7)
您可以利用与默认MVC AnchorTagHelper
相同的元素<a>
。您只需要确保在默认值之后在 _ViewImports.cshtml 中添加帮助程序:
@addTagHelper "*, Microsoft.AspNet.Mvc.TagHelpers"
@addTagHelper "*, WebApplication5"
然后,无论何时执行帮助,TagHelperOutput
都会包含默认AnchorTagHelper
使用asp-controller
和asp-action
生成的 href 标签
//Get url from href attribute generated by the default AnchorTagHelper
var url = output.Attributes["href"].Value.ToString();
然后,您可以将该网址与将为当前请求生成的网址进行比较:
var currentRoutUrl = this.urlHelper.Action();
最初我尝试了下面的代码,但在使用属性路由时它不起作用。我可以在路由值中看到一个带有键!__ route_group 的条目和一个异常 ArgumentException:已经添加了一个具有相同键的项:
var currentRouteUrl = this.urlHelper.RouteUrl( this.actionContextAccessor.ActionContext.RouteData.Values);
这样做而不是比较当前的请求网址是有原因的。这样,无论当前请求url是&#34; /&#34;或&#34; / Home / Index&#34;,在这两种情况下,您都会考虑为控制器主页和动作索引激活一个链接)
我按照这个想法创建了一个标签助手:
标记帮助器将用于定义了属性<a>
的{{1}}元素。 (这允许css类的属性是可选的,在这种情况下使用默认的活动类):
标记属性highlight-active
已从输出html
class属性与highlight-active
属性合并(也从输出html中删除)
代码如下:
css-active-class
因此,您现在可以在主页/索引页面中编写以下内容:
[HtmlTargetElement("a", Attributes = "highlight-active")]
public class RouteTagHelper : TagHelper
{
private IActionContextAccessor actionContextAccessor;
private IUrlHelper urlHelper;
public RouteTagHelper(IActionContextAccessor actionContextAccessor, IUrlHelper urlHelper)
{
this.actionContextAccessor = actionContextAccessor;
this.urlHelper = urlHelper;
}
//Optional attribute. If not defined, "active" class will be used
[HtmlAttributeName("css-active-class")]
public string CssClass { get; set; } = "active";
public override void Process(TagHelperContext context, TagHelperOutput output)
{
//Remove marker attribute
output.Attributes.Remove(output.Attributes["highlight-active"]);
//Get the url from href attribute generaed in the default AnchorTagHelper
var url = output.Attributes["href"].Value.ToString();
//Add active css class only when current request matches the generated href
var currentRouteUrl = this.urlHelper.Action();
if (url == currentRouteUrl)
{
var linkTag = new TagBuilder("a");
linkTag.Attributes.Add("class", this.CssClass);
output.MergeAttributes(linkTag);
}
}
}
呈现如下(无论当前网址是 / 或 /主页还是 /主页/索引):
<a class="menu" asp-controller="Home" asp-action="Index" highlight-active>Home</a>
<a class="menu" asp-controller="Home" asp-action="About" highlight-active>About</a>
<a class="menu" asp-controller="Home" asp-action="Index" highlight-active css-active-class="myActiveClass">Home with special class name</a>
<a class="menu" asp-controller="Home" asp-action="Index">Home using default tag helper</a>
PS。当您添加一个直接指定<a class="menu active" href="/">Home</a>
<a class="menu" href="/Home/About">About</a>
<a class="menu myActiveClass" href="/">Home with special class</a>
<a class="menu" href="/">Home using default tag helper</a>
属性的锚点时,您可能仍需要考虑这些情况(在调用href
之前,您可以检测是否已经有一个href)。在这种情况下,您可能还希望与当前URL进行比较(通过httpContext.Request)。
答案 1 :(得分:2)
虽然Daniel J.G的回答可能足以让任何人完成原始问题,但新官方documentation on TagHelpers指向TagHelperSamples project on GitHub,其中包含用于使用Bootstrap的Tag Helper示例。我只是想让你们知道这件事,它非常方便: - )
您可以像这样使用它:
<nav-link asp-controller="Home" asp-action="Index">
<a asp-controller="Home" asp-action="Index">Blog</a>
</nav-link>
&#13;
答案 2 :(得分:2)
DotNetCore 1.0快速而脏的更新......
[HtmlTargetElement("a", Attributes = "highlight-active")]
public class RouteTagHelper : TagHelper
{
[ViewContext]
public ViewContext ViewContext { get; set; }
private IUrlHelperFactory _urlHelper { get; set; }
public RouteTagHelper(IUrlHelperFactory urlHelper)
{
_urlHelper = urlHelper;
}
[HtmlAttributeName("css-active-class")]
public string CssClass { get; set; } = "active";
public override void Process(TagHelperContext context, TagHelperOutput output)
{
output.Attributes.Remove(output.Attributes["highlight-active"]);
var urlHelper = _urlHelper.GetUrlHelper(ViewContext);
var url = output.Attributes["href"].Value.ToString();
if (urlHelper.Action() == url)
{
var linkTag = new TagBuilder("a");
linkTag.Attributes.Add("class", this.CssClass);
output.MergeAttributes(linkTag);
}
}
}