确定Tag Helper中的当前路由。这可能吗?

时间:2015-10-02 17:22:37

标签: asp.net-core-mvc

在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

3 个答案:

答案 0 :(得分:7)

您可以利用与默认MVC AnchorTagHelper相同的元素<a>。您只需要确保在默认值之后在 _ViewImports.cshtml 中添加帮助程序:

@addTagHelper "*, Microsoft.AspNet.Mvc.TagHelpers"
@addTagHelper "*, WebApplication5"

然后,无论何时执行帮助,TagHelperOutput都会包含默认AnchorTagHelper使用asp-controllerasp-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示例。我只是想让你们知道这件事,它非常方便: - )

您可以像这样使用它:

&#13;
&#13;
<nav-link asp-controller="Home" asp-action="Index">
  <a asp-controller="Home" asp-action="Index">Blog</a>
</nav-link>
&#13;
&#13;
&#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);
        }
    }
}