Partilhar via


Componentes auxiliares de tag no ASP.NET Core

Por Scott Addie e Fiyaz Bin Hasan

Um componente auxiliar de tag é um auxiliar de tag que permite modificar condicionalmente ou adicionar elementos HTML do código do lado do servidor. Esse recurso está disponível no ASP.NET Core 2.0 ou posterior.

ASP.NET Core inclui dois componentes auxiliares de tag integrados: head e body. Eles estão localizados no Microsoft.AspNetCore.Mvc.Razor.TagHelpers namespace e podem ser usados no MVC e nas Razor Pages. Os componentes auxiliares de tags não exigem registro no aplicativo no _ViewImports.cshtml.

Visualizar ou descarregar amostra de código (como descarregar)

Casos de uso

Dois casos de uso comuns de componentes auxiliares de tags incluem:

  1. Injetando um <link> no <head>.
  2. Injetando um <script> no <body>.

As seções a seguir descrevem esses casos de uso.

Injetar no cabeçalho HTML

Dentro do elemento HTML <head> , os arquivos CSS são normalmente importados com o elemento HTML <link> . O código a seguir injeta um elemento <link> no elemento <head> usando o Componente Auxiliar de Marcação head.

using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.TagHelpers;

namespace RazorPagesSample.TagHelpers
{
    public class AddressStyleTagHelperComponent : TagHelperComponent
    {
        private readonly string _style = 
            @"<link rel=""stylesheet"" href=""/css/address.css"" />";

        public override int Order => 1;

        public override Task ProcessAsync(TagHelperContext context,
                                          TagHelperOutput output)
        {
            if (string.Equals(context.TagName, "head", 
                              StringComparison.OrdinalIgnoreCase))
            {
                output.PostContent.AppendHtml(_style);
            }

            return Task.CompletedTask;
        }
    }
}

No código anterior:

  • AddressStyleTagHelperComponent implementa TagHelperComponent. A abstração:
    • Permite inicializar a classe com um TagHelperContext.
    • Permite o uso de componentes auxiliares de tags para adicionar ou modificar elementos HTML.
  • A Order propriedade define a ordem na qual os componentes são renderizados. Order é necessário quando há vários usos de componentes auxiliares de tags em um aplicativo.
  • ProcessAsync compara o valor da propriedade do contexto de execução TagName com head. Se a comparação for avaliada como verdadeiro, o conteúdo do campo _style será injetado no elemento HTML <head>.

Injetar no elemento de corpo HTML

O componente auxiliar de tag body pode injetar um elemento <script> no elemento <body>. O código a seguir demonstra essa técnica:

using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.TagHelpers;

namespace RazorPagesSample.TagHelpers
{
    public class AddressScriptTagHelperComponent : TagHelperComponent
    {
        public override int Order => 2;
        
        public override async Task ProcessAsync(TagHelperContext context,
                                                TagHelperOutput output)
        {
            if (string.Equals(context.TagName, "body",
                              StringComparison.OrdinalIgnoreCase))
            {
                var script = await File.ReadAllTextAsync(
                    "TagHelpers/Templates/AddressToolTipScript.html");
                output.PostContent.AppendHtml(script);
            }
        }
    }
}

Um arquivo HTML separado é usado para armazenar o <script> elemento . O arquivo HTML torna o código mais limpo e mais fácil de manter. O código anterior lê o conteúdo de TagHelpers/Templates/AddressToolTipScript.html e acrescenta-o à saída do Tag Helper. O AddressToolTipScript.html arquivo inclui a seguinte marcação:

<script>
$("address[printable]").hover(function() {
    $(this).attr({
        "data-toggle": "tooltip",
        "data-placement": "right",
        "title": "Home of Microsoft!"
    });
});
</script>

O código anterior vincula um widget de dica de ferramenta Bootstrap a qualquer elemento <address> que inclua o atributo printable. O efeito é visível quando um ponteiro do mouse passa sobre o elemento.

Registrar um componente

Um componente auxiliar de tag deve ser adicionado à coleção de componentes auxiliares de tag do aplicativo. Há três maneiras de adicionar à coleção:

Registo através de contentor de serviços

Se a classe Tag Helper Component não for gerenciada com ITagHelperComponentManager, ela deverá ser registrada no sistema de injeção de dependência (DI ). O código a seguir Startup.ConfigureServices registra as AddressStyleTagHelperComponent classes e AddressScriptTagHelperComponent com um tempo de vida transitório:

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<CookiePolicyOptions>(options =>
    {
        options.CheckConsentNeeded = context => true;
        options.MinimumSameSitePolicy = SameSiteMode.None;
    });

    services.AddMvc()
            .SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

    services.AddTransient<ITagHelperComponent, 
        AddressScriptTagHelperComponent>();
    services.AddTransient<ITagHelperComponent, 
        AddressStyleTagHelperComponent>();
}

Registo via Razor ficheiro

Se o Componente Auxiliar de Tags não estiver registrado no DI, ele poderá ser registrado em uma Razor página do Pages ou em uma visualização MVC. Essa técnica é usada para controlar a marcação injetada e a ordem de execução do componente a partir de um Razor arquivo.

ITagHelperComponentManager é usado para adicionar componentes auxiliares de tag ou removê-los do aplicativo. O código a seguir demonstra essa técnica com AddressTagHelperComponent:

@using RazorPagesSample.TagHelpers;
@using Microsoft.AspNetCore.Mvc.Razor.TagHelpers;
@inject ITagHelperComponentManager manager;

@{
    string markup;

    if (Model.IsWeekend)
    {
        markup = "<em class='text-warning'>Office closed today!</em>";
    }
    else
    {
        markup = "<em class='text-info'>Office open today!</em>";
    }

    manager.Components.Add(new AddressTagHelperComponent(markup, 1));
}

No código anterior:

  • A @inject diretiva fornece um exemplo de ITagHelperComponentManager. A instância é atribuída a uma variável nomeada manager para acesso downstream no Razor arquivo.
  • Uma instância de AddressTagHelperComponent é adicionada à coleção de Componentes do Tag Helper do aplicativo.

AddressTagHelperComponent é modificado para acomodar um construtor que aceita os markup parâmetros e order :

private readonly string _markup;

public override int Order { get; }

public AddressTagHelperComponent(string markup = "", int order = 1)
{
    _markup = markup;
    Order = order;
}

O parâmetro fornecido markup é utilizado da ProcessAsync seguinte forma:

public override async Task ProcessAsync(TagHelperContext context,
                                        TagHelperOutput output)
{
    if (string.Equals(context.TagName, "address",
            StringComparison.OrdinalIgnoreCase) &&
        output.Attributes.ContainsName("printable"))
    {
        TagHelperContent childContent = await output.GetChildContentAsync();
        string content = childContent.GetContent();
        output.Content.SetHtmlContent(
            $"<div>{content}<br>{_markup}</div>{_printableButton}");
    }
}

Registo através do Modelo de Página ou controlador

Se o Componente Auxiliar de Tags não estiver registrado no DI, ele poderá ser registrado a partir de um Razor modelo de página do Pages ou de um controlador MVC. Essa técnica é útil para separar a lógica C# dos Razor arquivos.

A injeção do construtor é usada para acessar uma instância do ITagHelperComponentManager. O Componente Auxiliar de Tag é adicionado à coleção de Componentes Auxiliares de Tag da instância. O modelo de páginas denominado Pages Razor, a seguir, demonstra essa técnica com AddressTagHelperComponent:

using System;
using Microsoft.AspNetCore.Mvc.Razor.TagHelpers;
using Microsoft.AspNetCore.Mvc.RazorPages;
using RazorPagesSample.TagHelpers;

public class IndexModel : PageModel
{
    private readonly ITagHelperComponentManager _tagHelperComponentManager;

    public bool IsWeekend
    {
        get
        {
            var dayOfWeek = DateTime.Now.DayOfWeek;

            return dayOfWeek == DayOfWeek.Saturday ||
                   dayOfWeek == DayOfWeek.Sunday;
        }
    }

    public IndexModel(ITagHelperComponentManager tagHelperComponentManager)
    {
        _tagHelperComponentManager = tagHelperComponentManager;
    }

    public void OnGet()
    {
        string markup;

        if (IsWeekend)
        {
            markup = "<em class='text-warning'>Office closed today!</em>";
        }
        else
        {
            markup = "<em class='text-info'>Office open today!</em>";
        }

        _tagHelperComponentManager.Components.Add(
            new AddressTagHelperComponent(markup, 1));
    }
}

No código anterior:

  • A injeção do construtor é usada para acessar uma instância do ITagHelperComponentManager.
  • Uma instância de AddressTagHelperComponent é adicionada à coleção de Componentes do Tag Helper do aplicativo.

Criar um componente

Para criar um componente auxiliar de tag personalizado:

O código a seguir cria um componente auxiliar de marca personalizado que tem como alvo o <address> elemento HTML:

using System.ComponentModel;
using Microsoft.AspNetCore.Mvc.Razor.TagHelpers;
using Microsoft.AspNetCore.Razor.TagHelpers;
using Microsoft.Extensions.Logging;

namespace RazorPagesSample.TagHelpers
{
    [HtmlTargetElement("address")]
    [EditorBrowsable(EditorBrowsableState.Never)]
    public class AddressTagHelperComponentTagHelper : TagHelperComponentTagHelper
    {
        public AddressTagHelperComponentTagHelper(
            ITagHelperComponentManager componentManager, 
            ILoggerFactory loggerFactory) : base(componentManager, loggerFactory)
        {
        }
    }
}

Use o componente auxiliar de tag personalizado address para injetar a marcação HTML da seguinte maneira:

public class AddressTagHelperComponent : TagHelperComponent
{
    private readonly string _printableButton =
        "<button type='button' class='btn btn-info' onclick=\"window.open(" +
        "'https://binged.it/2AXRRYw')\">" +
        "<span class='glyphicon glyphicon-road' aria-hidden='true'></span>" +
        "</button>";

    public override int Order => 3;

    public override async Task ProcessAsync(TagHelperContext context,
                                            TagHelperOutput output)
    {
        if (string.Equals(context.TagName, "address",
                StringComparison.OrdinalIgnoreCase) &&
            output.Attributes.ContainsName("printable"))
        {
            var content = await output.GetChildContentAsync();
            output.Content.SetHtmlContent(
                $"<div>{content.GetContent()}</div>{_printableButton}");
        }
    }
}

O método anterior ProcessAsync injeta o HTML fornecido para SetHtmlContent no elemento correspondente <address>. A injeção ocorre quando:

  • O valor da propriedade do contexto de execução TagName é igual a address.
  • O elemento correspondente <address> tem um printable atributo.

Por exemplo, a if instrução é avaliada como true ao processar o seguinte <address> elemento:

<address printable>
    One Microsoft Way<br />
    Redmond, WA 98052-6399<br />
    <abbr title="Phone">P:</abbr>
    425.555.0100
</address>

Recursos adicionais