Compartilhar via


Componentes Razor no ASP.NET Core

Observação

Esta não é a versão mais recente deste artigo. Para informações sobre a versão vigente, confira a Versão do .NET 8 deste artigo.

Aviso

Esta versão do ASP.NET Core não tem mais suporte. Para obter mais informações, confira .NET e a Política de Suporte do .NET Core. Para informações sobre a versão vigente, confira a Versão do .NET 8 deste artigo.

Importante

Essas informações relacionam-se ao produto de pré-lançamento, que poderá ser substancialmente modificado antes do lançamento comercial. A Microsoft não oferece nenhuma garantia, explícita ou implícita, quanto às informações fornecidas aqui.

Para informações sobre a versão vigente, confira a Versão do .NET 8 deste artigo.

Este artigo explica como criar e usar componentes Razor em aplicativos Blazor, incluindo diretrizes sobre a sintaxe Razor, a nomenclatura de componentes, namespaces e parâmetros de componente.

Componentes Razor

Os aplicativos Blazor são internos utilizando Razor componentes, informalmente conhecidos como Blazor componentes ou apenas componentes. Um componente é uma parte independente da interface do usuário com lógica de processamento para habilitar comportamento dinâmico. Os componentes podem ser aninhados, reutilizados, compartilhados entre projetos e usados em aplicativos MVC e Razor Pages.

Os componentes são renderizados em uma representação na memória do Modelo de Objeto do Documento (DOM) do navegador chamada árvore de renderização, que é usada para atualizar a interface do usuário de maneira flexível e eficiente.

Embora os "componentes Razor" compartilhem alguns nomes com outras tecnologias de renderização de conteúdo do ASP.NET Core, os componentes Razor devem ser diferenciados dos seguintes recursos diferentes no ASP.NET Core:

  • Razor exibições, que são páginas de marcação baseadas em Razor para aplicativos MVC.
  • Exibir componentes, que servem para renderizar partes de conteúdo em vez de respostas inteiras em Razor Páginas e aplicativos MVC.

Importante

Ao usar um Blazor Web App, a maioria dos componentes de exemplo de documentação do Blazor requerem interatividade para funcionar e demonstrar os conceitos abordados pelos artigos. Ao testar um componente de exemplo fornecido por um artigo, verifique se o aplicativo adota interatividade global ou se o componente adota um modo de renderização interativo. Mais informações sobre esse assunto são fornecidas pelos modos de renderização Blazor do ASP.NET Core, que é o próximo artigo no sumário após este artigo.

Classes de componentes

Os componentes são implementados usando uma combinação de marcação C# e HTML em arquivos de componente Razor com a extensão de arquivo .razor.

ComponentBase é a classe base dos componentes descritos por arquivos de componente Razor. ComponentBase implementa a abstração mais baixa de componentes, a interface IComponent. ComponentBase define propriedades de componente e métodos para funcionalidade básica, por exemplo, para processar um conjunto de eventos internos de ciclo de vida do componente.

ComponentBase na fonte de referência dotnet/aspnetcore: a fonte de referência contém comentários adicionais sobre os eventos internos de ciclo de vida. No entanto, tenha em mente que as implementações internas dos recursos de componente estão sujeitas a alterações a qualquer momento sem aviso prévio.

Observação

Os links de documentação para a fonte de referência do .NET geralmente carregam o branch padrão do repositório, que representa o desenvolvimento atual da próxima versão do .NET. Para selecionar uma marca para uma versão específica, use a lista suspensa para Alternar branches ou marcas. Para saber mais, confira Como selecionar uma marca de versão do código-fonte do ASP.NET Core (dotnet/AspNetCore.Docs #26205).

Os desenvolvedores normalmente criam componentes Razorde arquivos de componente Razor (.razor) ou baseiam seus componentes em ComponentBase, mas os componentes também podem ser criados implementando IComponent. Os componentes criados pelo desenvolvedor que implementam IComponent podem ter controle de baixo nível sobre a renderização ao custo de ter que disparar manualmente a renderização com eventos e métodos de ciclo de vida que o desenvolvedor deve criar e manter.

Você pode encontrar convenções adicionais adotadas pelo código de exemplo de documentação e pelos aplicativos de exemplo do Blazor em Princípios básicos do ASP.NETBlazor.

Sintaxe de Razor

Os componentes usam a sintaxe Razor. Dois recursos Razor são amplamente usados pelos componentes: diretivas e atributos de diretiva. Trata-se de palavras-chave reservadas prefixadas com @ que aparecem na marcação Razor:

  • Diretivas: alteram a forma como a marcação do componente é compilada ou funciona. Por exemplo, a diretiva @page especifica um componente roteável com um modelo de rota que pode ser acessado diretamente pela solicitação de um usuário no navegador em uma URL específica.

    Por convenção, as diretivas de um componente na parte superior de uma definição de componente (arquivo .razor) são posicionadas em uma ordem consistente. Para diretivas repetidas, as diretivas são posicionadas em ordem alfabética por namespace ou tipo, exceto as diretivas @using, que têm uma ordenação especial de segundo nível.

    A ordem a seguir é adotada por Blazor aplicativos de amostra e documentação. Os componentes fornecidos por um modelo de projeto Blazor podem ser diferentes da ordem a seguir e usar um formato diferente. Por exemplo, os componentes Blazor da estrutura Identity incluem linhas em branco entre blocos de diretivas @using e blocos de diretivas @inject. Você é livre para usar um esquema de ordenação e formato personalizados em seus próprios aplicativos.

    Documentação e ordem de diretiva do aplicativo Razor de exemplo:

    • @page
    • @rendermode (.NET 8 ou posterior)
    • @using
      • System namespaces (ordem alfabética)
      • Microsoft namespaces (ordem alfabética)
      • Namespaces de API de terceiros (ordem alfabética)
      • Namespaces de aplicativo (ordem alfabética)
    • Outras diretivas (ordem alfabética)

    Não aparecem linhas em branco entre as diretivas. Uma linha em branco aparece entre as diretivas e a primeira linha de marcação Razor.

    Exemplo:

    @page "/doctor-who-episodes/{season:int}"
    @rendermode InteractiveWebAssembly
    @using System.Globalization
    @using System.Text.Json
    @using Microsoft.AspNetCore.Localization
    @using Mandrill
    @using BlazorSample.Components.Layout
    @attribute [Authorize]
    @implements IAsyncDisposable
    @inject IJSRuntime JS
    @inject ILogger<DoctorWhoEpisodes> Logger
    
    <PageTitle>Doctor Who Episode List</PageTitle>
    
    ...
    
  • Atributos de diretiva: alteram a forma como um elemento de componente é compilado ou funciona.

    Exemplo:

    <input @bind="episodeId" />
    

    Você pode prefixar valores de atributo de diretiva com o símbolo (@) para expressões de Razor não explícitas (@bind="@episodeId"), mas não recomendamos e os documentos não adotam a abordagem em exemplos.

As diretivas e os atributos de diretiva usados nos componentes são explicados mais adiante neste artigo e em outros artigos do conjunto de documentação Blazor. Para obter informações gerais sobre a sintaxe Razor, confira a Referência da sintaxe Razor para ASP.NET Core.

Nome do componente, nome da classe e namespace

O nome de um componente precisa começar com um caractere maiúsculo:

Com suporte: ProductDetail.razor

Sem suporte: productDetail.razor

Convenções de nomenclatura Blazor comuns usadas em toda a documentação de Blazor incluem:

  • Os caminhos e nomes de arquivos utilizam as maiúsculas e minúsculas† do Pascal e aparecem antes de mostrar os códigos de exemplo. Se um caminho estiver presente, ele indicará o local típico da pasta. Por exemplo, Components/Pages/ProductDetail.razor indica que o componente ProductDetail tem um nome de arquivo ProductDetail.razor e reside na pasta Pages da pasta Components do aplicativo.
  • Os caminhos de arquivo de componentes roteáveis correspondem às suas URLs em letras maiúsculas e minúsculas‡ com hifens aparecendo entre as palavras no modelo da rota de um componente. Por exemplo, um componente ProductDetail com um modelo de rota /product-detail (@page "/product-detail") é solicitado em um navegador na URL relativa /product-detail.

PascalCase† (camelCase iniciada por maiúscula) é uma convenção de nomenclatura sem espaços e pontuação e com a primeira letra de cada palavra maiúscula, incluindo a primeira palavra.
‡Kebab case é uma convenção de nomes sem espaços e pontuação que utiliza letras minúsculas e traços entre as palavras.

Os componentes são classes C# comuns e podem ser colocados em qualquer lugar de um projeto. Componentes que produzem páginas da Web geralmente residem na pasta Components/Pages. Frequentemente, componentes que não são de página são colocados na pasta Components ou em uma pasta personalizada adicionada ao projeto.

Normalmente, o namespace de um componente é derivado do namespace raiz do aplicativo e da localização do componente (pasta) no aplicativo. Se o namespace raiz do aplicativo for BlazorSample e o componente Counter residir na pasta Components/Pages:

  • O namespace do componente Counter será BlazorSample.Components.Pages.
  • O nome do tipo totalmente qualificado do componente será BlazorSample.Components.Pages.Counter.

Para pastas personalizadas que contêm componentes, adicione uma diretiva @using ao componente pai ou ao arquivo _Imports.razor do aplicativo. O seguinte exemplo disponibiliza componentes na pasta AdminComponents:

@using BlazorSample.AdminComponents

Observação

As diretivas @using no arquivo _Imports.razor são aplicadas somente a arquivos Razor (.razor), não a arquivos C# (.cs).

As atribuições de alias using são suportadas. No exemplo a seguir, a classe pública WeatherForecast do componente GridRendering é disponibilizada como WeatherForecast em um componente em outro lugar do aplicativo:

@using WeatherForecast = Components.Pages.GridRendering.WeatherForecast

Os componentes também podem ser referenciados usando os respectivos nomes totalmente qualificados, o que não requer uma diretiva @using. O seguinte exemplo faz referência direta ao componente ProductDetail na pasta AdminComponents/Pages do aplicativo:

<BlazorSample.AdminComponents.Pages.ProductDetail />

O namespace de um componente criado com Razor é baseado no seguinte (em ordem de prioridade):

  • A diretiva @namespace na marcação do arquivo Razor (por exemplo, @namespace BlazorSample.CustomNamespace).
  • O projeto RootNamespace está no arquivo de projeto (por exemplo, <RootNamespace>BlazorSample</RootNamespace>).
  • O namespace do projeto e o caminho da raiz do projeto até o componente. Por exemplo, a estrutura resolve {PROJECT NAMESPACE}/Components/Pages/Home.razor com um namespace de projeto BlazorSample para o namespace BlazorSample.Components.Pages do componente Home. {PROJECT NAMESPACE} é o namespace do projeto. Os componentes seguem as regras de associação de nome em C#. Para o componente Home neste exemplo, os componentes no escopo são todos:
    • Na mesma pasta, Components/Pages.
    • Os componentes na raiz do projeto que não especificam explicitamente um namespace diferente.

Não há suporte para o seguinte:

  • A qualificação global::.
  • Nomes parcialmente qualificados. Por exemplo, você não pode adicionar @using BlazorSample.Components a um componente e, depois, referenciar o componente NavMenu na pasta do Components/Layout aplicativo (Components/Layout/NavMenu.razor) com <Layout.NavMenu></Layout.NavMenu>.

O nome de um componente precisa começar com um caractere maiúsculo:

Com suporte: ProductDetail.razor

Sem suporte: productDetail.razor

Convenções de nomenclatura Blazor comuns usadas em toda a documentação de Blazor incluem:

  • Os caminhos e nomes de arquivos utilizam as maiúsculas e minúsculas† do Pascal e aparecem antes de mostrar os códigos de exemplo. Se um caminho estiver presente, ele indicará o local típico da pasta. Por exemplo, Pages/ProductDetail.razor indica que o componente ProductDetail tem um nome de arquivo ProductDetail.razor e reside na pasta Pages do aplicativo.
  • Os caminhos de arquivo de componentes roteáveis correspondem às suas URLs em letras maiúsculas e minúsculas‡ com hifens aparecendo entre as palavras no modelo da rota de um componente. Por exemplo, um componente ProductDetail com um modelo de rota /product-detail (@page "/product-detail") é solicitado em um navegador na URL relativa /product-detail.

PascalCase† (camelCase iniciada por maiúscula) é uma convenção de nomenclatura sem espaços e pontuação e com a primeira letra de cada palavra maiúscula, incluindo a primeira palavra.
‡Kebab case é uma convenção de nomes sem espaços e pontuação que utiliza letras minúsculas e traços entre as palavras.

Os componentes são classes C# comuns e podem ser colocados em qualquer lugar de um projeto. Componentes que produzem páginas da Web geralmente residem na pasta Pages. Frequentemente, componentes que não são de página são colocados na pasta Shared ou em uma pasta personalizada adicionada ao projeto.

Normalmente, o namespace de um componente é derivado do namespace raiz do aplicativo e da localização do componente (pasta) no aplicativo. Se o namespace raiz do aplicativo for BlazorSample e o componente Counter residir na pasta Pages:

  • O namespace do componente Counter será BlazorSample.Pages.
  • O nome do tipo totalmente qualificado do componente será BlazorSample.Pages.Counter.

Para pastas personalizadas que contêm componentes, adicione uma diretiva @using ao componente pai ou ao arquivo _Imports.razor do aplicativo. O seguinte exemplo disponibiliza componentes na pasta AdminComponents:

@using BlazorSample.AdminComponents

Observação

As diretivas @using no arquivo _Imports.razor são aplicadas somente a arquivos Razor (.razor), não a arquivos C# (.cs).

As atribuições de alias using são suportadas. No exemplo a seguir, a classe pública WeatherForecast do componente GridRendering é disponibilizada como WeatherForecast em um componente em outro lugar do aplicativo:

@using WeatherForecast = Pages.GridRendering.WeatherForecast

Os componentes também podem ser referenciados usando os respectivos nomes totalmente qualificados, o que não requer uma diretiva @using. O seguinte exemplo faz referência direta ao componente ProductDetail na pasta Components do aplicativo:

<BlazorSample.Components.ProductDetail />

O namespace de um componente criado com Razor é baseado no seguinte (em ordem de prioridade):

  • A diretiva @namespace na marcação do arquivo Razor (por exemplo, @namespace BlazorSample.CustomNamespace).
  • O projeto RootNamespace está no arquivo de projeto (por exemplo, <RootNamespace>BlazorSample</RootNamespace>).
  • O namespace do projeto e o caminho da raiz do projeto até o componente. Por exemplo, a estrutura resolve {PROJECT NAMESPACE}/Pages/Index.razor com um namespace de projeto BlazorSample para o namespace BlazorSample.Pages do componente Index. {PROJECT NAMESPACE} é o namespace do projeto. Os componentes seguem as regras de associação de nome em C#. Para o componente Index neste exemplo, os componentes no escopo são todos:
    • Na mesma pasta, Pages.
    • Os componentes na raiz do projeto que não especificam explicitamente um namespace diferente.

Não há suporte para o seguinte:

  • A qualificação global::.
  • Nomes parcialmente qualificados. Por exemplo, você não pode adicionar @using BlazorSample a um componente e, depois, referenciar o componente NavMenu na pasta do Shared aplicativo (Shared/NavMenu.razor) com <Shared.NavMenu></Shared.NavMenu>.

Suporte para classe parcial

Os componentes são gerados como classes parciais de C# e são criados usando uma das seguintes abordagens:

  • Um arquivo contém o código C# definido em um ou mais blocos @code, marcação HTML e marcação Razor. Os modelos de projeto Blazor definem os respectivos componentes usando essa abordagem de arquivo único.
  • O HTML e a marcação Razor são colocados em um arquivo Razor (.razor). O código C# é colocado em um arquivo code-behind definido como uma classe parcial (.cs).

Observação

A folha de estilos de um componente que define estilos específicos do componente é um arquivo separado (.css). O isolamento de CSS Blazor é descrito posteriormente em Isolamento de CSS de Blazor no ASP.NET Core.

O exemplo a seguir mostra o componente padrão Counter com um bloco @code em um aplicativo gerado com base em um modelo de projeto Blazor. A marcação e o código C# ficam no mesmo arquivo. Essa é a abordagem mais comum adotada na criação de componentes.

Counter.razor:

@page "/counter"

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

<p role="status">Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    private int currentCount = 0;

    private void IncrementCount() => currentCount++;
}
@page "/counter"

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

<p role="status">Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
    }
}
@page "/counter"

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

<p role="status">Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
    }
}
@page "/counter"

<h1>Counter</h1>

<p>Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
    }
}
@page "/counter"

<h1>Counter</h1>

<p>Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
    }
}

O componente Counter a seguir divide a apresentação HTML e a marcação Razor do código C# utilizando um arquivo code-behind com uma classe parcial. Algumas organizações e desenvolvedores preferem separar a marcação do código C# para organizar o código do componente de acordo com a forma como preferem trabalhar. Por exemplo, o especialista em interface do usuário da organização pode trabalhar na camada de apresentação independentemente de outro desenvolvedor que esteja trabalhando na logica C# do componente. A abordagem também é útil quando se trabalha com código gerado automaticamente ou geradores de origens. Para obter mais informações, confira Classes e Métodos Parciais (Guia de Programação C#).

CounterPartialClass.razor:

@page "/counter-partial-class"

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

<p role="status">Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@page "/counter-partial-class"

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

<p role="status">Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@page "/counter-partial-class"

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

<p role="status">Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@page "/counter-partial-class"

<h1>Counter</h1>

<p>Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@page "/counter-partial-class"

<h1>Counter</h1>

<p>Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

CounterPartialClass.razor.cs:

namespace BlazorSample.Components.Pages;

public partial class CounterPartialClass
{
    private int currentCount = 0;

    private void IncrementCount() => currentCount++;
}
namespace BlazorSample.Pages;

public partial class CounterPartialClass
{
    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
    }
}
namespace BlazorSample.Pages
{
    public partial class CounterPartialClass
    {
        private int currentCount = 0;

        private void IncrementCount()
        {
            currentCount++;
        }
    }
}

As diretivas @using no arquivo _Imports.razor são aplicadas somente a arquivos Razor (.razor), não a arquivos C# (.cs). Adicione os namespaces a um arquivo de classe parcial conforme necessário.

Namespaces típicos usados pelos componentes:

using System.Net.Http;
using System.Net.Http.Json;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.AspNetCore.Components.Routing;
using Microsoft.AspNetCore.Components.Sections
using Microsoft.AspNetCore.Components.Web;
using static Microsoft.AspNetCore.Components.Web.RenderMode;
using Microsoft.AspNetCore.Components.Web.Virtualization;
using Microsoft.JSInterop;

Namespaces típicos também incluem o namespace do aplicativo e o namespace correspondente à pasta Components do aplicativo:

using BlazorSample;
using BlazorSample.Components;

Pastas adicionais também podem ser incluídas, como a pasta Layout:

using BlazorSample.Components.Layout;
using System.Net.Http;
using System.Net.Http.Json;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.AspNetCore.Components.Routing;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.Web.Virtualization;
using Microsoft.JSInterop;

Namespaces típicos também incluem o namespace do aplicativo e o namespace correspondente à pasta Shared do aplicativo:

using BlazorSample;
using BlazorSample.Shared;
using System.Net.Http;
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.AspNetCore.Components.Routing;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.JSInterop;

Namespaces típicos também incluem o namespace do aplicativo e o namespace correspondente à pasta Shared do aplicativo:

using BlazorSample;
using BlazorSample.Shared;

Especificar uma classe base

A diretiva @inherits é usada para especificar uma classe base para um componente. Ao contrário do uso de classes parciais, que apenas separam a marcação da logica do C#, o uso de uma classe base permite herdar o código do C# para uso em um grupo de componentes que compartilham as propriedades e os métodos da classe base. O uso de classes de base reduz a redundância do código nos aplicativos e é útil ao fornecer códigos de base de bibliotecas de classes para vários aplicativos. Para obter mais informações, confira Herança em C# e .NET.

No exemplo a seguir, a classe base BlazorRocksBase1 deriva de ComponentBase.

BlazorRocks1.razor:

@page "/blazor-rocks-1"
@inherits BlazorRocksBase1

<PageTitle>Blazor Rocks!</PageTitle>

<h1>Blazor Rocks! Example 1</h1>

<p>
    @BlazorRocksText
</p>
@page "/blazor-rocks-1"
@inherits BlazorRocksBase1

<PageTitle>Blazor Rocks!</PageTitle>

<h1>Blazor Rocks! Example 1</h1>

<p>
    @BlazorRocksText
</p>
@page "/blazor-rocks-1"
@inherits BlazorRocksBase1

<PageTitle>Blazor Rocks!</PageTitle>

<h1>Blazor Rocks! Example 1</h1>

<p>
    @BlazorRocksText
</p>
@page "/blazor-rocks-1"
@inherits BlazorRocksBase1

<h1>Blazor Rocks! Example 1</h1>

<p>
    @BlazorRocksText
</p>
@page "/blazor-rocks-1"
@inherits BlazorRocksBase1

<h1>Blazor Rocks! Example 1</h1>

<p>
    @BlazorRocksText
</p>

BlazorRocksBase1.cs:

using Microsoft.AspNetCore.Components;

namespace BlazorSample;

public class BlazorRocksBase1 : ComponentBase
{
    public string BlazorRocksText { get; set; } = "Blazor rocks the browser!";
}
using Microsoft.AspNetCore.Components;

namespace BlazorSample;

public class BlazorRocksBase1 : ComponentBase
{
    public string BlazorRocksText { get; set; } =
        "Blazor rocks the browser!";
}
using Microsoft.AspNetCore.Components;

namespace BlazorSample;

public class BlazorRocksBase1 : ComponentBase
{
    public string BlazorRocksText { get; set; } =
        "Blazor rocks the browser!";
}
using Microsoft.AspNetCore.Components;

namespace BlazorSample;

public class BlazorRocksBase1 : ComponentBase
{
    public string BlazorRocksText { get; set; } =
        "Blazor rocks the browser!";
}
using Microsoft.AspNetCore.Components;

namespace BlazorSample;

public class BlazorRocksBase1 : ComponentBase
{
    public string BlazorRocksText { get; set; } =
        "Blazor rocks the browser!";
}

Roteamento

O roteamento em Blazor é realizado fornecendo um modelo de rota para cada componente acessível no aplicativo com uma diretiva @page. Quando um arquivo Razor com uma diretiva @page é compilado, a classe gerada recebe um RouteAttribute especificando o modelo da rota. No runtime, o roteador pesquisa por classes de componente com um RouteAttribute e renderiza qualquer componente que tenha um modelo de rota correspondente à URL solicitada.

O componente HelloWorld a seguir usa um modelo de rota de /hello-world e a página da Web renderizada para o componente é atingida na URL relativa /hello-world.

HelloWorld.razor:

@page "/hello-world"

<PageTitle>Hello World!</PageTitle>

<h1>Hello World!</h1>
@page "/hello-world"

<h1>Hello World!</h1>
@page "/hello-world"

<h1>Hello World!</h1>
@page "/hello-world"

<h1>Hello World!</h1>
@page "/hello-world"

<h1>Hello World!</h1>

O componente anterior é carregado no navegador /hello-world, independentemente de você adicioná-lo à navegação da interface do usuário do aplicativo. Opcionalmente, os componentes podem ser adicionados ao componente NavMenu para que um link para o componente apareça na navegação baseada em interface do usuário do aplicativo.

Para o componente HelloWorld anterior, você pode adicionar um componente NavLink ao componente NavMenu. Para obter mais informações, incluindo descrições dos componentes NavLink e NavMenu, consulte Roteamento e navegação de Blazor no ASP.NET Core.

Marcação

A interface do usuário de um componente é definida usando a sintaxe Razor, composta por marcação Razor, C# e HTML. Quando um aplicativo é compilado, a marcação HTML e a lógica de renderização de C# são convertidas em uma classe de componente. O nome da classe gerada corresponde ao nome do arquivo.

Os membros da classe de componente são definidos em um ou mais blocos @code. Nos blocos @code, o estado do componente é especificado e processado com C#:

  • Inicializadores de propriedade e de campo.
  • Valores de parâmetro de argumentos passados por parâmetros de rota e componentes pai.
  • Métodos para tratamento de eventos do usuário, eventos de ciclo de vida e lógica de componente personalizada.

Os membros do componente são usados na lógica de renderização usando expressões em C# que começam com o símbolo @. Por exemplo, um campo C# é renderizado adicionando o prefixo @ ao nome do campo. O seguinte componente Markup avalia e renderiza:

  • headingFontStyle para o valor font-style da propriedade CSS do elemento de título.
  • headingText para o conteúdo do elemento de título.

Markup.razor:

@page "/markup"

<PageTitle>Markup</PageTitle>

<h1>Markup Example</h1>

<h2 style="font-style:@headingFontStyle">@headingText</h2>

@code {
    private string headingFontStyle = "italic";
    private string headingText = "Put on your new Blazor!";
}
@page "/markup"

<h1 style="font-style:@headingFontStyle">@headingText</h1>

@code {
    private string headingFontStyle = "italic";
    private string headingText = "Put on your new Blazor!";
}
@page "/markup"

<h1 style="font-style:@headingFontStyle">@headingText</h1>

@code {
    private string headingFontStyle = "italic";
    private string headingText = "Put on your new Blazor!";
}
@page "/markup"

<h1 style="font-style:@headingFontStyle">@headingText</h1>

@code {
    private string headingFontStyle = "italic";
    private string headingText = "Put on your new Blazor!";
}
@page "/markup"

<h1 style="font-style:@headingFontStyle">@headingText</h1>

@code {
    private string headingFontStyle = "italic";
    private string headingText = "Put on your new Blazor!";
}

Observação

Exemplos ao longo da documentação de Blazor especificam o modificador de acesso private para membros privados. Membros privados têm como escopo a classe de um componente. No entanto, C# pressupõe o modificador de acesso private quando nenhum modificador de acesso está presente, portanto, marcar explicitamente os membros "private" em seu código é opcional. Para obter mais informações sobre os modificadores de acesso, consulte Modificadores de acesso (Guia de programação em C#).

A estrutura Blazor processa um componente internamente como uma árvore de renderização, que é a combinação do DOM de um componente e do Modelo de Objeto da Folha de Estilo em Cascata (CSSOM). Após o componente ser renderizado inicialmente, a árvore de renderização dele é regenerada em resposta a eventos. O Blazor compara a nova árvore de renderização com a anterior e aplica as modificações ao DOM do navegador para exibição. Para saber mais, consulte Renderização de componentes de Razor no ASP.NET Core.

A sintaxe Razor para estruturas de controle, diretivas e atributos de diretiva em C# é em minúsculas (por exemplo, @if, @code, @bind). Os nomes de propriedade são em maiúsculas (por exemplo, @Body para LayoutComponentBase.Body).

Métodos assíncronos (async) não dão suporte ao retorno de void

A estrutura Blazor não acompanha métodos assíncronos com retorno de void (async). Como resultado, exceções não serão capturadas se void for retornado. Sempre retorne um Task de métodos assíncronos.

Componentes aninhados

Os componentes podem incluir outros componentes declarando-os usando a sintaxe HTML. A marcação para uso de um componente é semelhante a uma marca HTML, em que o nome da marca é o tipo de componente.

Considere o componente Heading a seguir, que pode ser usado por outros componentes para exibir um título.

Heading.razor:

<h1 style="font-style:@headingFontStyle">Heading Example</h1>

@code {
    private string headingFontStyle = "italic";
}
<h1 style="font-style:@headingFontStyle">Heading Example</h1>

@code {
    private string headingFontStyle = "italic";
}
<h1 style="font-style:@headingFontStyle">Heading Example</h1>

@code {
    private string headingFontStyle = "italic";
}
<h1 style="font-style:@headingFontStyle">Heading Example</h1>

@code {
    private string headingFontStyle = "italic";
}
<h1 style="font-style:@headingFontStyle">Heading Example</h1>

@code {
    private string headingFontStyle = "italic";
}

A marcação a seguir no componente HeadingExample renderiza o componente Heading anterior no local em que a marca <Heading /> é exibida.

HeadingExample.razor:

@page "/heading-example"

<PageTitle>Heading</PageTitle>

<h1>Heading Example</h1>

<Heading />
@page "/heading-example"

<Heading />
@page "/heading-example"

<Heading />
@page "/heading-example"

<Heading />
@page "/heading-example"

<Heading />

Se um componente contiver um elemento HTML com uma primeira letra maiúscula que não corresponde a um nome de componente no mesmo namespace, será emitido um aviso indicando que o elemento tem um nome inesperado. Adicionar um diretiva @using para o namespace do componente disponibiliza o componente, o que resolve o aviso. Para obter mais informações, confira a seção Nome do componente, nome da classe e namespace.

O componente de exemplo Heading mostrado nesta seção não tem uma diretiva @page, portanto o componente Heading não é diretamente acessível a um usuário por meio de uma solicitação direta no navegador. No entanto, qualquer componente com uma diretiva @page pode ser aninhado em outro componente. Se o componente Heading estivesse diretamente acessível, com a inclusão de @page "/heading" na parte superior do arquivo Razor, ele seria renderizado para solicitações de navegador em /heading e /heading-example.

Parâmetros do componente

Os parâmetros de componente passam dados para os componentes e são definidos usando propriedades C# públicas na classe de componente com o atributo [Parameter]. No exemplo a seguir, um tipo de referência interno (System.String) e um tipo de referência definido pelo usuário (PanelBody) são passados como parâmetros de componente.

PanelBody.cs:

namespace BlazorSample;

public class PanelBody
{
    public string? Text { get; set; }
    public string? Style { get; set; }
}
public class PanelBody
{
    public string? Text { get; set; }
    public string? Style { get; set; }
}
public class PanelBody
{
    public string? Text { get; set; }
    public string? Style { get; set; }
}
public class PanelBody
{
    public string Text { get; set; }
    public string Style { get; set; }
}
public class PanelBody
{
    public string Text { get; set; }
    public string Style { get; set; }
}

ParameterChild.razor:

<div class="card w-25" style="margin-bottom:15px">
    <div class="card-header font-weight-bold">@Title</div>
    <div class="card-body" style="font-style:@Body.Style">
        @Body.Text
    </div>
</div>

@code {
    [Parameter]
    public string Title { get; set; } = "Set By Child";

    [Parameter]
    public PanelBody Body { get; set; } =
        new()
        {
            Text = "Card content set by child.",
            Style = "normal"
        };
}
<div class="card w-25" style="margin-bottom:15px">
    <div class="card-header font-weight-bold">@Title</div>
    <div class="card-body" style="font-style:@Body.Style">
        @Body.Text
    </div>
</div>

@code {
    [Parameter]
    public string Title { get; set; } = "Set By Child";

    [Parameter]
    public PanelBody Body { get; set; } =
        new()
        {
            Text = "Set by child.",
            Style = "normal"
        };
}
<div class="card w-25" style="margin-bottom:15px">
    <div class="card-header font-weight-bold">@Title</div>
    <div class="card-body" style="font-style:@Body.Style">
        @Body.Text
    </div>
</div>

@code {
    [Parameter]
    public string Title { get; set; } = "Set By Child";

    [Parameter]
    public PanelBody Body { get; set; } =
        new()
        {
            Text = "Set by child.",
            Style = "normal"
        };
}
<div class="card w-25" style="margin-bottom:15px">
    <div class="card-header font-weight-bold">@Title</div>
    <div class="card-body" style="font-style:@Body.Style">
        @Body.Text
    </div>
</div>

@code {
    [Parameter]
    public string Title { get; set; } = "Set By Child";

    [Parameter]
    public PanelBody Body { get; set; } =
        new()
        {
            Text = "Set by child.",
            Style = "normal"
        };
}
<div class="card w-25" style="margin-bottom:15px">
    <div class="card-header font-weight-bold">@Title</div>
    <div class="card-body" style="font-style:@Body.Style">
        @Body.Text
    </div>
</div>

@code {
    [Parameter]
    public string Title { get; set; } = "Set By Child";

    [Parameter]
    public PanelBody Body { get; set; } =
        new PanelBody()
        {
            Text = "Set by child.",
            Style = "normal"
        };
}

Aviso

Há suporte para fornecer valores iniciais para os parâmetros de componente, mas não crie um componente que grava nos próprios parâmetros após ter sido renderizado pela primeira vez. Para obter mais informações, confira Evitar a substituição de parâmetros no ASP.NET Core Blazor.

Os parâmetros Title e Body do componente ParameterChild são definidos por argumentos na marca HTML que renderiza a instância do componente. O seguinte componente ParameterParent renderiza dois componentes ParameterChild:

  • O primeiro componente ParameterChild é renderizado sem fornecer argumentos de parâmetro.
  • O segundo componente ParameterChild recebe valores de Title e Body do componente ParameterParent, que usa uma expressão C# explícita para definir os valores das propriedades PanelBody.

Parameter1.razor:

@page "/parameter-1"

<PageTitle>Parameter 1</PageTitle>

<h1>Parameter Example 1</h1>

<h1>Child component (without attribute values)</h1>

<ParameterChild />

<h1>Child component (with attribute values)</h1>

<ParameterChild Title="Set by Parent" 
    Body="@(new PanelBody() { Text = "Set by parent.", Style = "italic" })" />

ParameterParent.razor:

@page "/parameter-parent"

<h1>Child component (without attribute values)</h1>

<ParameterChild />

<h1>Child component (with attribute values)</h1>

<ParameterChild Title="Set by Parent"
                Body="@(new PanelBody() { Text = "Set by parent.", Style = "italic" })" />

ParameterParent.razor:

@page "/parameter-parent"

<h1>Child component (without attribute values)</h1>

<ParameterChild />

<h1>Child component (with attribute values)</h1>

<ParameterChild Title="Set by Parent"
                Body="@(new PanelBody() { Text = "Set by parent.", Style = "italic" })" />

ParameterParent.razor:

@page "/parameter-parent"

<h1>Child component (without attribute values)</h1>

<ParameterChild />

<h1>Child component (with attribute values)</h1>

<ParameterChild Title="Set by Parent"
                Body="@(new PanelBody() { Text = "Set by parent.", Style = "italic" })" />

ParameterParent.razor:

@page "/parameter-parent"

<h1>Child component (without attribute values)</h1>

<ParameterChild />

<h1>Child component (with attribute values)</h1>

<ParameterChild Title="Set by Parent"
                Body="@(new PanelBody() { Text = "Set by parent.", Style = "italic" })" />

A marcação HTML renderizada a seguir do componente ParameterParent mostra valores padrão do componente ParameterChild quando o componente ParameterParent não fornece valores de parâmetro de componente. Quando o componente ParameterParent fornece valores de parâmetro de componente, eles substituem os valores padrão do componente ParameterChild.

Observação

Para maior clareza, as classes de estilo CSS renderizadas não são mostradas na marcação HTML renderizada a seguir.

<h1>Child component (without attribute values)</h1>

<div>
    <div>Set By Child</div>
    <div>Set by child.</div>
</div>

<h1>Child component (with attribute values)</h1>

<div>
    <div>Set by Parent</div>
    <div>Set by parent.</div>
</div>

Atribua um campo, uma propriedade ou o resultado de um método C# a um parâmetro de componente como um valor de atributo HTML. O valor do atributo normalmente pode ser qualquer expressão C# que corresponda ao tipo do parâmetro. O valor do atributo pode, opcionalmente, começar com um símbolo reservado Razor@, mas não é necessário.

Se o parâmetro de componente for do tipo cadeia de caracteres, o valor do atributo será tratado como um literal de cadeia de caracteres C#. Se você quiser especificar uma expressão C#, use o prefixo @.

O seguinte componente ParameterParent2 exibe quatro instâncias do componente ParameterChild anterior e define os respectivos valores de parâmetro Title como:

  • O valor do campo title.
  • O resultado do método C# GetTitle.
  • A data local atual em formato longo com ToLongDateString, que usa uma expressão C# implícita.
  • O valor da propriedade Title do objeto panelData.

As aspas em torno dos valores de atributo do parâmetro são opcionais na maioria dos casos, de acordo com a especificação HTML5. Por exemplo, há suporte para Value=this em vez de Value="this". No entanto, é recomendável usar aspas, porque é mais fácil de lembrar e amplamente adotado entre tecnologias baseadas na Web.

Ao longo da documentação, em exemplos de código:

  • Sempre use aspas. Exemplo: Value="this".
  • Não use o prefixo @ com não literais, a menos que necessário. Exemplo: Count="ct", em que ct é uma variável de tipo de número. Count="@ct" é uma abordagem estilística válida, mas a documentação e os exemplos não adotam a convenção.
  • Sempre evite @ para literais, fora de expressões Razor. Exemplo: IsFixed="true". Isso inclui palavras-chave (por exemplo, this) e null, mas você pode optar por usá-las se desejar. Por exemplo, IsFixed="@true" é incomum, mas tem suporte.

Parameter2.razor:

@page "/parameter-2"

<PageTitle>Parameter 2</PageTitle>

<h1>Parameter Example 2</h1>

<ParameterChild Title="@title" />

<ParameterChild Title="@GetTitle()" />

<ParameterChild Title="@DateTime.Now.ToLongDateString()" />

<ParameterChild Title="@panelData.Title" />

@code {
    private string title = "From Parent field";
    private PanelData panelData = new();

    private string GetTitle() => "From Parent method";

    private class PanelData
    {
        public string Title { get; set; } = "From Parent object";
    }
}

ParameterParent2.razor:

@page "/parameter-parent-2"

<ParameterChild Title="@title" />

<ParameterChild Title="@GetTitle()" />

<ParameterChild Title="@DateTime.Now.ToLongDateString()" />

<ParameterChild Title="@panelData.Title" />

@code {
    private string title = "From Parent field";
    private PanelData panelData = new();

    private string GetTitle()
    {
        return "From Parent method";
    }

    private class PanelData
    {
        public string Title { get; set; } = "From Parent object";
    }
}

ParameterParent2.razor:

@page "/parameter-parent-2"

<ParameterChild Title="@title" />

<ParameterChild Title="@GetTitle()" />

<ParameterChild Title="@DateTime.Now.ToLongDateString()" />

<ParameterChild Title="@panelData.Title" />

@code {
    private string title = "From Parent field";
    private PanelData panelData = new();

    private string GetTitle()
    {
        return "From Parent method";
    }

    private class PanelData
    {
        public string Title { get; set; } = "From Parent object";
    }
}

ParameterParent2.razor:

@page "/parameter-parent-2"

<ParameterChild Title="@title" />

<ParameterChild Title="@GetTitle()" />

<ParameterChild Title="@DateTime.Now.ToLongDateString()" />

<ParameterChild Title="@panelData.Title" />

@code {
    private string title = "From Parent field";
    private PanelData panelData = new PanelData();

    private string GetTitle()
    {
        return "From Parent method";
    }

    private class PanelData
    {
        public string Title { get; set; } = "From Parent object";
    }
}

Observação

Ao atribuir um membro C# a um parâmetro de componente, não prefixe o atributo HTML do parâmetro com @.

Correto (Title é um parâmetro de cadeia de caracteres, Count é um parâmetro de tipo de número):

<ParameterChild Title="@title" Count="ct" />
<ParameterChild Title="@title" Count="@ct" />

Incorreto:

<ParameterChild @Title="@title" @Count="ct" />
<ParameterChild @Title="@title" @Count="@ct" />

Diferente das páginas Razor (.cshtml), Blazor não é capaz de executar trabalho assíncrono em uma expressão Razor ao renderizar um componente. Isso ocorre porque Blazor foi projetado para renderizar UIs interativas. Em uma interface do usuário interativa, a tela deve sempre exibir algo, de modo que não faz sentido bloquear o fluxo de renderização. Em vez disso, o trabalho assíncrono é executado durante um dos eventos de ciclo de vida assíncronos. Após cada evento de ciclo de vida assíncrono, o componente pode ser renderizado novamente. A seguinte sintaxe Razor não tem suporte:

<ParameterChild Title="await ..." />
<ParameterChild Title="@await ..." />

O código no exemplo anterior gera um erro do compilador quando o aplicativo é criado:

O operador 'await' só pode ser usado dentro de um método assíncrono. Considere marcar esse método com o modificador 'async' e alterar seu tipo de retorno para 'Task'.

Para obter um valor para o parâmetro Title no exemplo anterior de maneira assíncrona, o componente pode usar o evento de ciclo de vida OnInitializedAsync, como demonstra o seguinte exemplo:

<ParameterChild Title="@title" />

@code {
    private string? title;
    
    protected override async Task OnInitializedAsync()
    {
        title = await ...;
    }
}

Para saber mais, consulte Ciclo de vida de renderização de Razor no ASP.NET Core.

Não há suporte para o uso de uma expressão Razor explícita para concatenar texto com um resultado de expressão para atribuição a um parâmetro. O exemplo a seguir busca concatenar o texto "Set by " com o valor da propriedade de um objeto. Embora essa sintaxe tenha suporte em uma página Razor (.cshtml), ela não é válida para atribuição ao parâmetro Title do filho em um componente. A seguinte sintaxe Razor não tem suporte:

<ParameterChild Title="Set by @(panelData.Title)" />

O código no exemplo anterior gera um erro do compilador quando o aplicativo é criado:

Os atributos de componente não dão suporte a conteúdo complexo (C# misto e marcação).

Para dar suporte à atribuição de um valor composto, use um método, um campo ou uma propriedade. O seguinte exemplo executa a concatenação de "Set by " e o valor da propriedade de um objeto no método C# GetTitle:

Parameter3.razor:

@page "/parameter-3"

<PageTitle>Parameter 3</PageTitle>

<h1>Parameter Example 3</h1>

<ParameterChild Title="@GetTitle()" />

@code {
    private PanelData panelData = new();

    private string GetTitle() => $"Set by {panelData.Title}";

    private class PanelData
    {
        public string Title { get; set; } = "Parent";
    }
}

ParameterParent3.razor:

@page "/parameter-parent-3"

<ParameterChild Title="@GetTitle()" />

@code {
    private PanelData panelData = new();

    private string GetTitle() => $"Set by {panelData.Title}";

    private class PanelData
    {
        public string Title { get; set; } = "Parent";
    }
}

ParameterParent3.razor:

@page "/parameter-parent-3"

<ParameterChild Title="@GetTitle()" />

@code {
    private PanelData panelData = new();

    private string GetTitle() => $"Set by {panelData.Title}";

    private class PanelData
    {
        public string Title { get; set; } = "Parent";
    }
}

ParameterParent3.razor:

@page "/parameter-parent-3"

<ParameterChild Title="@GetTitle()" />

@code {
    private PanelData panelData = new();

    private string GetTitle() => $"Set by {panelData.Title}";

    private class PanelData
    {
        public string Title { get; set; } = "Parent";
    }
}

ParameterParent3.razor:

@page "/parameter-parent-3"

<ParameterChild Title="@GetTitle()" />

@code {
    private PanelData panelData = new PanelData();

    private string GetTitle() => $"Set by {panelData.Title}";

    private class PanelData
    {
        public string Title { get; set; } = "Parent";
    }
}

Para obter mais informações, consulte a Referência da sintaxe Razor para ASP.NET Core.

Aviso

Há suporte para fornecer valores iniciais para os parâmetros de componente, mas não crie um componente que grava nos próprios parâmetros após ter sido renderizado pela primeira vez. Para obter mais informações, confira Evitar a substituição de parâmetros no ASP.NET Core Blazor.

Os parâmetros de componente devem ser declarados como propriedades automáticas, o que significa que não devem conter lógica personalizada nos acessadores get ou set. Por exemplo, a seguinte propriedade StartData é uma propriedade automática:

[Parameter]
public DateTime StartData { get; set; }

Não coloque lógica personalizada no acessador get ou set, porque os parâmetros de componente são puramente destinados ao uso como um canal para um componente pai fluir informações para um componente filho. Se um acessador set de uma propriedade de componente filho contiver lógica que cause a repetição da renderização do componente pai, um loop de renderização infinito ocorrerá.

Para transformar um valor de parâmetro recebido:

  • Deixe a propriedade de parâmetro como uma propriedade automática para representar os dados brutos fornecidos.
  • Crie uma propriedade ou método diferente para fornecer os dados transformados com base na propriedade do parâmetro.

Substitua OnParametersSetAsync para transformar um parâmetro recebido sempre que novos dados forem recebidos.

Há suporte para gravar um valor inicial em um parâmetro de componente porque atribuições de valor inicial não interferem na renderização de componente automática de Blazor. A seguinte atribuição do local atual DateTime com DateTime.Now para StartData é uma sintaxe válida em um componente:

[Parameter]
public DateTime StartData { get; set; } = DateTime.Now;

Após a atribuição inicial de DateTime.Now, não atribua um valor a StartData no código do desenvolvedor. Para obter mais informações, confira Evitar a substituição de parâmetros no ASP.NET Core Blazor.

Aplique o atributo [EditorRequired] para especificar um parâmetro de componente necessário. Se um valor de parâmetro não for fornecido, editores ou ferramentas de build poderão exibir avisos ao usuário. Esse atributo é válido somente em propriedades também marcadas com o atributo [Parameter]. O EditorRequiredAttribute é imposto em tempo de design e quando o aplicativo é criado. O atributo não é imposto no runtime e não garante um valor de parâmetro diferente de null.

[Parameter]
[EditorRequired]
public string? Title { get; set; }

Também há suporte para listas de atributos de linha única:

[Parameter, EditorRequired]
public string? Title { get; set; }

Não utilize o modificador required ou o acessador init nas propriedades dos parâmetros do componente. Em geral, os componentes são instanciados e recebem valores de parâmetros utilizando o reflexão, o que contorna as garantias que init e required foram projetadas para oferecer. Em vez disso, utilize o atributo [EditorRequired] para especificar um parâmetro de componente exigido.

Não use o acessador init nas propriedades dos parâmetros do componente, pois a configuração dos valores dos parâmetros do componente com ParameterView.SetParameterProperties utiliza o reflexão, o que contorna a restrição do setter somente init. Utilize o atributo [EditorRequired] para especificar um parâmetro de componente exigido.

Não use o acessador init nas propriedades dos parâmetros do componente, pois a configuração dos valores dos parâmetros do componente com ParameterView.SetParameterProperties utiliza o reflexão, o que contorna a restrição do setter somente init.

Tuples (documentação da API) têm suporte para parâmetros de componente e tipos RenderFragment. O seguinte exemplo de parâmetro de componente passa três valores em um Tuple:

RenderTupleChild.razor:

<div class="card w-50" style="margin-bottom:15px">
    <div class="card-header font-weight-bold">Tuple Card</div>
    <div class="card-body">
        <ul>
            <li>Integer: @Data?.Item1</li>
            <li>String: @Data?.Item2</li>
            <li>Boolean: @Data?.Item3</li>
        </ul>
    </div>
</div>

@code {
    [Parameter]
    public (int, string, bool)? Data { get; set; }
}

RenderTupleParent.razor:

@page "/render-tuple-parent"

<PageTitle>Render Tuple Parent</PageTitle>

<h1>Render Tuple Parent Example</h1>

<RenderTupleChild Data="data" />

@code {
    private (int, string, bool) data = new(999, "I aim to misbehave.", true);
}

As tuplas nomeadas são suportadas, conforme verificado no exemplo a seguir:

NamedTupleChild.razor:

<div class="card w-50" style="margin-bottom:15px">
    <div class="card-header font-weight-bold">Tuple Card</div>
    <div class="card-body">
        <ul>
            <li>Integer: @Data?.TheInteger</li>
            <li>String: @Data?.TheString</li>
            <li>Boolean: @Data?.TheBoolean</li>
        </ul>
    </div>
</div>

@code {
    [Parameter]
    public (int TheInteger, string TheString, bool TheBoolean)? Data { get; set; }
}

NamedTuples.razor:

@page "/named-tuples"

<PageTitle>Named Tuples</PageTitle>

<h1>Named Tuples Example</h1>

<NamedTupleChild Data="data" />

@code {
    private (int TheInteger, string TheString, bool TheBoolean) data = 
        new(999, "I aim to misbehave.", true);
}

Aspas ©2005 Universal Pictures: Serenity (Nathan Fillion)

Tuples (documentação da API) têm suporte para parâmetros de componente e tipos RenderFragment. O seguinte exemplo de parâmetro de componente passa três valores em um Tuple:

RenderTupleChild.razor:

<div class="card w-50" style="margin-bottom:15px">
    <div class="card-header font-weight-bold"><code>Tuple</code> Card</div>
    <div class="card-body">
        <ul>
            <li>Integer: @Data?.Item1</li>
            <li>String: @Data?.Item2</li>
            <li>Boolean: @Data?.Item3</li>
        </ul>
    </div>
</div>

@code {
    [Parameter]
    public (int, string, bool)? Data { get; set; }
}

RenderTupleParent.razor:

@page "/render-tuple-parent"

<h1>Render Tuple Parent</h1>

<RenderTupleChild Data="data" />

@code {
    private (int, string, bool) data = new(999, "I aim to misbehave.", true);
}

As tuplas nomeadas são suportadas, conforme verificado no exemplo a seguir:

RenderNamedTupleChild.razor:

<div class="card w-50" style="margin-bottom:15px">
    <div class="card-header font-weight-bold"><code>Tuple</code> Card</div>
    <div class="card-body">
        <ul>
            <li>Integer: @Data?.TheInteger</li>
            <li>String: @Data?.TheString</li>
            <li>Boolean: @Data?.TheBoolean</li>
        </ul>
    </div>
</div>

@code {
    [Parameter]
    public (int TheInteger, string TheString, bool TheBoolean)? Data { get; set; }
}

RenderNamedTupleParent.razor:

@page "/render-named-tuple-parent"

<h1>Render Named Tuple Parent</h1>

<RenderNamedTupleChild Data="data" />

@code {
    private (int TheInteger, string TheString, bool TheBoolean) data = 
        new(999, "I aim to misbehave.", true);
}

Aspas ©2005 Universal Pictures: Serenity (Nathan Fillion)

Parâmetros de rota

Os componentes podem especificar parâmetros de rota no modelo de rota da diretiva @page. O roteador Blazor usa parâmetros de rota para preencher parâmetros de componente correspondentes.

RouteParameter1.razor:

@page "/route-parameter-1/{text}"

<PageTitle>Route Parameter 1</PageTitle>

<h1>Route Parameter Example 1</h1>

<p>Blazor is @Text!</p>

@code {
    [Parameter]
    public string? Text { get; set; }
}
@page "/route-parameter-1/{text}"

<h1>Blazor is @Text!</h1>

@code {
    [Parameter]
    public string? Text { get; set; }
}
@page "/route-parameter-1/{text}"

<h1>Blazor is @Text!</h1>

@code {
    [Parameter]
    public string? Text { get; set; }
}
@page "/route-parameter-1/{text}"

<h1>Blazor is @Text!</h1>

@code {
    [Parameter]
    public string Text { get; set; }
}
@page "/route-parameter-1/{text}"

<h1>Blazor is @Text!</h1>

@code {
    [Parameter]
    public string Text { get; set; }
}

Para obter mais informações, confira a seção Parâmetros de rota de Roteamento e navegação do ASP.NET Core Blazor. Parâmetros de rota opcionais também têm suporte e são abordados na mesma seção. Para obter informações sobre parâmetros de rota abrangentes ({*pageRoute}), que capturam caminhos entre vários limites de pasta, confira a seção Parâmetros de rota abrangentes de Roteamento e navegação do ASP.NET Core Blazor.

Para obter mais informações, confira a seção Parâmetros de rota de Roteamento e navegação do ASP.NET Core Blazor. Não há suporte para parâmetros de rota opcionais, portanto, duas diretivas @page são necessárias (confira a seção Parâmetros de rota para obter mais informações). Para obter informações sobre parâmetros de rota abrangentes ({*pageRoute}), que capturam caminhos entre vários limites de pasta, confira a seção Parâmetros de rota abrangentes de Roteamento e navegação do ASP.NET Core Blazor.

Aviso

Com a compressão, que está habilitada por padrão, evite criar componentes interativos seguros (autenticados/autorizados) do lado do servidor que renderizam dados de fontes não confiáveis. As fontes não confiáveis incluem parâmetros de rota, cadeias de caracteres de consulta, dados de interoperação com JS e qualquer outra fonte de dados que um usuário de terceiros possa controlar (bancos de dados, serviços externos). Para obter mais informações, consulte ASP.NET Core BlazorSignalRDiretrizes e Orientações de mitigação de ameaças para o ASP.NET Core Blazor renderização interativa do lado do servidor.

Fragmentos de renderização de conteúdo filho

Os componentes podem definir o conteúdo de outro componente. O componente de atribuição fornece o conteúdo entre as marcas de abertura e fechamento do componente filho.

No exemplo a seguir, o componente RenderFragmentChild tem um parâmetro de componente ChildContent que representa um segmento da interface do usuário a ser renderizado como um RenderFragment. A posição de ChildContent marcação do componente Razor é onde o conteúdo é renderizado na saída HTML final.

RenderFragmentChild.razor:

<div class="card w-25" style="margin-bottom:15px">
    <div class="card-header font-weight-bold">Child content</div>
    <div class="card-body">@ChildContent</div>
</div>

@code {
    [Parameter]
    public RenderFragment? ChildContent { get; set; }
}
<div class="card w-25" style="margin-bottom:15px">
    <div class="card-header font-weight-bold">Child content</div>
    <div class="card-body">@ChildContent</div>
</div>

@code {
    [Parameter]
    public RenderFragment? ChildContent { get; set; }
}
<div class="card w-25" style="margin-bottom:15px">
    <div class="card-header font-weight-bold">Child content</div>
    <div class="card-body">@ChildContent</div>
</div>

@code {
    [Parameter]
    public RenderFragment? ChildContent { get; set; }
}
<div class="card w-25" style="margin-bottom:15px">
    <div class="card-header font-weight-bold">Child content</div>
    <div class="card-body">@ChildContent</div>
</div>

@code {
    [Parameter]
    public RenderFragment ChildContent { get; set; }
}
<div class="card w-25" style="margin-bottom:15px">
    <div class="card-header font-weight-bold">Child content</div>
    <div class="card-body">@ChildContent</div>
</div>

@code {
    [Parameter]
    public RenderFragment ChildContent { get; set; }
}

Importante

A propriedade que recebe o conteúdo RenderFragment deve ser nomeada ChildContent por convenção.

Não há suporte para retornos de chamada de evento para RenderFragment.

O componente a seguir fornece conteúdo para renderização do RenderFragmentChild, posicionando o conteúdo dentro das marcas de abertura e fechamento do componente filho.

RenderFragments.razor:

@page "/render-fragments"

<PageTitle>Render Fragments</PageTitle>

<h1>Render Fragments Example</h1>

<RenderFragmentChild>
    Content of the child component is supplied
    by the parent component.
</RenderFragmentChild>

RenderFragmentParent.razor:

@page "/render-fragment-parent"

<h1>Render child content</h1>

<RenderFragmentChild>
    Content of the child component is supplied
    by the parent component.
</RenderFragmentChild>

RenderFragmentParent.razor:

@page "/render-fragment-parent"

<h1>Render child content</h1>

<RenderFragmentChild>
    Content of the child component is supplied
    by the parent component.
</RenderFragmentChild>

RenderFragmentParent.razor:

@page "/render-fragment-parent"

<h1>Render child content</h1>

<RenderFragmentChild>
    Content of the child component is supplied
    by the parent component.
</RenderFragmentChild>

RenderFragmentParent.razor:

@page "/render-fragment-parent"

<h1>Render child content</h1>

<RenderFragmentChild>
    Content of the child component is supplied
    by the parent component.
</RenderFragmentChild>

Os fragmentos de renderização são usados para renderizar conteúdo filho em aplicativos Blazor e são descritos com exemplos nos seguintes artigos e seções de artigo:

Observação

Os componentes internosRazor da estrutura Blazor usam a mesma convenção de parâmetro de componente ChildContent para definir seu conteúdo. Você pode ver os componentes que definem o conteúdo filho pesquisando pelo nome ChildContent da propriedade de parâmetro do componente na Documentação da API (filtra a API pelo termo de pesquisa "ChildContent").

Fragmentos de renderização para lógica de renderização reutilizável

Você pode fatorar componentes filho puramente como uma forma de reutilizar a lógica de renderização. No bloco @code de qualquer componente, defina um RenderFragment e renderize o fragmento de qualquer local quantas vezes forem necessárias:

@RenderWelcomeInfo

<p>Render the welcome info a second time:</p>

@RenderWelcomeInfo

@code {
    private RenderFragment RenderWelcomeInfo =  @<p>Welcome to your new app!</p>;
}

Para obter mais informações, consulte Reutilizar a lógica de renderização.

Variáveis de loop com parâmetros de componente e conteúdo filho

Para renderizar componentes dentro de um loop for é necessário uma variável de índice local se a variável de loop de incremento for usada pelos parâmetros do componente ou pelo conteúdo filho RenderFragment.

Considere o componente a seguir RenderFragmentChild2 que tem um parâmetro de componente (Id) e um fragmento de renderização para exibir o conteúdo filho (ChildContent).

RenderFragmentChild2.razor:

<div class="card w-25" style="margin-bottom:15px">
    <div class="card-header font-weight-bold">Child content (@Id)</div>
    <div class="card-body">@ChildContent</div>
</div>

@code {
    [Parameter]
    public string? Id { get; set; }

    [Parameter]
    public RenderFragment? ChildContent { get; set; }
}

Ao renderizar o componente RenderFragmentChild2 em um componente pai, use uma variável de índice local (ct no exemplo a seguir) em vez da variável de loop (c) ao atribuir o valor do parâmetro do componente e fornecer o conteúdo do componente filho:

@for (int c = 1; c < 4; c++)
{
    var ct = c;

    <RenderFragmentChild2 Id="@($"Child{ct}")">
        Count: @ct
    </RenderFragmentChild2>
}

Como alternativa, use um loop foreach com Enumerable.Range em vez de um loop for:

@foreach (var c in Enumerable.Range(1, 3))
{
    <RenderFragmentChild2 Id="@($"Child{c}")">
        Count: @c
    </RenderFragmentChild2>
}

Capturar referências a componentes

Referências a componentes proporcionam uma maneira de fazer referência a uma instância de componente para emitir comandos. Para capturar uma referência a um componente:

  • Adicione um atributo @ref ao componente filho.
  • Defina um campo com o mesmo tipo que o componente filho.

Quando o componente é renderizado, o campo é preenchido com a instância do componente. Em seguida, você pode invocar métodos .NET na instância.

Considere o componente ReferenceChild a seguir que registra uma mensagem quando seu ChildMethod é chamado.

ReferenceChild.razor:

@inject ILogger<ReferenceChild> Logger

@if (value > 0)
{
    <p>
        <code>value</code>: @value
    </p>
}

@code {
    private int value;

    public void ChildMethod(int value)
    {
        Logger.LogInformation("Received {Value} in ChildMethod", value);

        this.value = value;
        StateHasChanged();
    }
}
@using Microsoft.Extensions.Logging
@inject ILogger<ReferenceChild> Logger

@code {
    public void ChildMethod(int value)
    {
        Logger.LogInformation("Received {Value} in ChildMethod", value);
    }
}
@using Microsoft.Extensions.Logging
@inject ILogger<ReferenceChild> Logger

@code {
    public void ChildMethod(int value)
    {
        Logger.LogInformation("Received {Value} in ChildMethod", value);
    }
}
@using Microsoft.Extensions.Logging
@inject ILogger<ReferenceChild> Logger

@code {
    public void ChildMethod(int value)
    {
        Logger.LogInformation("Received {Value} in ChildMethod", value);
    }
}
@using Microsoft.Extensions.Logging
@inject ILogger<ReferenceChild> Logger

@code {
    public void ChildMethod(int value)
    {
        Logger.LogInformation("Received {Value} in ChildMethod", value);
    }
}

Uma referência de componente só é preenchida depois que o componente é renderizado e sua saída inclui o elemento de ReferenceChild. Até que o componente seja renderizado, não há nada a que fazer referência. Não tente chamar um método de componente referenciado diretamente para um manipulador de eventos (por exemplo, @onclick="childComponent!.ChildMethod(5)") porque a variável de referência pode não ser atribuída no momento em que o evento clique é atribuído.

Para manipular referências de componente após a renderização do componente, use os métodos OnAfterRender ou OnAfterRenderAsync.

O exemplo a seguir usa o ReferenceChild component anterior.

ReferenceParent.razor:

@page "/reference-parent"

<div>
    <button @onclick="@(() => childComponent1!.ChildMethod(5))">
        Call <code>ReferenceChild.ChildMethod</code> (first instance) 
        with an argument of 5
    </button>

    <ReferenceChild @ref="childComponent1" />
</div>

<div>
    <button @onclick="CallChildMethod">
        Call <code>ReferenceChild.ChildMethod</code> (second instance) 
        with an argument of 5
    </button>

    <ReferenceChild @ref="childComponent2" />
</div>

@code {
    private ReferenceChild? childComponent1;
    private ReferenceChild? childComponent2;

    private void CallChildMethod() => childComponent2!.ChildMethod(5);
}
@page "/reference-parent"

<div>
    <button @onclick="@(() => childComponent1!.ChildMethod(5))">
        Call <code>ReferenceChild.ChildMethod</code> (first instance) 
        with an argument of 5
    </button>

    <ReferenceChild @ref="childComponent1" />
</div>

<div>
    <button @onclick="CallChildMethod">
        Call <code>ReferenceChild.ChildMethod</code> (second instance) 
        with an argument of 5
    </button>

    <ReferenceChild @ref="childComponent2" />
</div>

@code {
    private ReferenceChild? childComponent1;
    private ReferenceChild? childComponent2;

    private void CallChildMethod()
    {
        childComponent2!.ChildMethod(5);
    }
}
@page "/reference-parent"

<div>
    <button @onclick="@(() => childComponent1!.ChildMethod(5))">
        Call <code>ReferenceChild.ChildMethod</code> (first instance) 
        with an argument of 5
    </button>

    <ReferenceChild @ref="childComponent1" />
</div>

<div>
    <button @onclick="CallChildMethod">
        Call <code>ReferenceChild.ChildMethod</code> (second instance) 
        with an argument of 5
    </button>

    <ReferenceChild @ref="childComponent2" />
</div>

@code {
    private ReferenceChild? childComponent1;
    private ReferenceChild? childComponent2;

    private void CallChildMethod()
    {
        childComponent2!.ChildMethod(5);
    }
}
@page "/reference-parent"

<div>
    <button @onclick="@(() => childComponent1!.ChildMethod(5))">
        Call <code>ReferenceChild.ChildMethod</code> (first instance) 
        with an argument of 5
    </button>

    <ReferenceChild @ref="childComponent1" />
</div>

<div>
    <button @onclick="CallChildMethod">
        Call <code>ReferenceChild.ChildMethod</code> (second instance) 
        with an argument of 5
    </button>

    <ReferenceChild @ref="childComponent2" />
</div>

@code {
    private ReferenceChild childComponent1;
    private ReferenceChild childComponent2;

    private void CallChildMethod()
    {
        childComponent2!.ChildMethod(5);
    }
}
@page "/reference-parent"

<div>
    <button @onclick="@(() => childComponent1!.ChildMethod(5))">
        Call <code>ReferenceChild.ChildMethod</code> (first instance) 
        with an argument of 5
    </button>

    <ReferenceChild @ref="childComponent1" />
</div>

<div>
    <button @onclick="CallChildMethod">
        Call <code>ReferenceChild.ChildMethod</code> (second instance) 
        with an argument of 5
    </button>

    <ReferenceChild @ref="childComponent2" />
</div>

@code {
    private ReferenceChild childComponent1;
    private ReferenceChild childComponent2;

    private void CallChildMethod()
    {
        childComponent2!.ChildMethod(5);
    }
}

Embora a captura de referências de componentes use uma sintaxe semelhante para capturar referências de elementos, capturar referências de componentes não é um recurso de interoperabilidade de JavaScript. As referências de componente não são passadas para o código JavaScript. As referências de componente são usadas apenas no código .NET.

Importante

Não use referências de componente para alterar o estado dos componentes filho. Em vez disso, use parâmetros de componente declarativos normais para passar dados para componentes filho. O uso de parâmetros de componente resulta em componentes filho que são renderizados novamente, nos horários corretos, automaticamente. Para obter mais informações, consulte a seção parâmetros de componente e o artigo Associação de dados Blazor do ASP.NET Core.

Aplicar um atributo

Os atributos podem ser aplicados a componentes com a diretiva @attribute. O seguinte exemplo aplica o atributo [Authorize] à classe do componente:

@page "/"
@attribute [Authorize]

Atributos dos elementos em HTML condicionais e propriedades do DOM

Blazor adota os seguintes comportamentos gerais:

  • Para os atributos em HTML, Blazor defina ou remova o atributo condicionalmente com base no valor do .NET. Se o valor do .NET for false ou null, o atributo não será definido ou será removido se tiver sido definido anteriormente.
  • Para as propriedades do DOM, como checked ou value, Blazor defina a propriedade do DOM com base no valor do .NET. Se o valor do .NET for false ou null, a propriedade do DOM será redefinida para um valor padrão.

Quais atributos de sintaxe Razor correspondem aos atributos em HTML e quais correspondem às propriedades do DOM ainda não estão documentados porque isso é detalhe de implementação da estrutura que pode ser alterado sem aviso prévio.

Aviso

Alguns atributos em HTML, como aria-pressed, devem ter um valor da cadeia de caracteres "true" ou "false". Como eles exigem um valor da cadeia de caracteres e não um booliano, você deve usar um string do .NET e não um bool para seu valor. Esse é um requisito definido pelas APIs do DOM do navegador.

HTML bruto

Normalmente, as cadeias de caracteres são renderizadas usando nós de texto DOM, o que significa que qualquer marcação que elas possam conter é ignorada e tratada como texto literal. Para renderizar HTML bruto, encapsule o conteúdo HTML em um valor MarkupString. O valor é analisado como HTML ou SVG e inserido no DOM.

Aviso

Renderizar HTML bruto construído de qualquer fonte não confiável é um risco de segurança e sempre deve ser evitado.

O exemplo a seguir mostra o uso do tipo MarkupString para adicionar um bloco de conteúdo HTML estático à saída renderizada de um componente.

MarkupStrings.razor:

@page "/markup-strings"

<PageTitle>Markup Strings</PageTitle>

<h1>Markup Strings Example</h1>

@((MarkupString)myMarkup)

@code {
    private string myMarkup =
        "<p class=\"text-danger\">This is a dangerous <em>markup string</em>.</p>";
}

MarkupStringExample.razor:

@page "/markup-string-example"

@((MarkupString)myMarkup)

@code {
    private string myMarkup =
        "<p class=\"text-danger\">This is a dangerous <em>markup string</em>.</p>";
}

MarkupStringExample.razor:

@page "/markup-string-example"

@((MarkupString)myMarkup)

@code {
    private string myMarkup =
        "<p class=\"text-danger\">This is a dangerous <em>markup string</em>.</p>";
}

MarkupStringExample.razor:

@page "/markup-string-example"

@((MarkupString)myMarkup)

@code {
    private string myMarkup =
        "<p class=\"text-danger\">This is a dangerous <em>markup string</em>.</p>";
}

MarkupStringExample.razor:

@page "/markup-string-example"

@((MarkupString)myMarkup)

@code {
    private string myMarkup =
        "<p class=\"text-danger\">This is a dangerous <em>markup string</em>.</p>";
}

Modelos Razor

Fragmentos de renderização podem ser definidos usando a sintaxe do modelo Razor para definir um snippet de interface do usuário. Os modelos Razor usam o seguinte formato:

@<{HTML tag}>...</{HTML tag}>

O exemplo a seguir ilustra como especificar valores de RenderFragment e RenderFragment<TValue> e renderizar modelos diretamente em um componente. Fragmentos de renderização também podem ser passados como argumentos para componentes de modelo.

RazorTemplate.razor:

@page "/razor-template"

<PageTitle>Razor Template</PageTitle>

<h1>Razor Template Example</h1>

@timeTemplate

@petTemplate(new Pet { Name = "Nutty Rex" })

@code {
    private RenderFragment timeTemplate = @<p>The time is @DateTime.Now.</p>;
    private RenderFragment<Pet> petTemplate = (pet) => @<p>Pet: @pet.Name</p>;

    private class Pet
    {
        public string? Name { get; set; }
    }
}
@page "/razor-template"

@timeTemplate

@petTemplate(new Pet { Name = "Nutty Rex" })

@code {
    private RenderFragment timeTemplate = @<p>The time is @DateTime.Now.</p>;
    private RenderFragment<Pet> petTemplate = (pet) => @<p>Pet: @pet.Name</p>;

    private class Pet
    {
        public string? Name { get; set; }
    }
}
@page "/razor-template"

@timeTemplate

@petTemplate(new Pet { Name = "Nutty Rex" })

@code {
    private RenderFragment timeTemplate = @<p>The time is @DateTime.Now.</p>;
    private RenderFragment<Pet> petTemplate = (pet) => @<p>Pet: @pet.Name</p>;

    private class Pet
    {
        public string? Name { get; set; }
    }
}
@page "/razor-template"

@timeTemplate

@petTemplate(new Pet { Name = "Nutty Rex" })

@code {
    private RenderFragment timeTemplate = @<p>The time is @DateTime.Now.</p>;
    private RenderFragment<Pet> petTemplate = (pet) => @<p>Pet: @pet.Name</p>;

    private class Pet
    {
        public string Name { get; set; }
    }
}
@page "/razor-template"

@timeTemplate

@petTemplate(new Pet { Name = "Nutty Rex" })

@code {
    private RenderFragment timeTemplate = @<p>The time is @DateTime.Now.</p>;
    private RenderFragment<Pet> petTemplate = (pet) => @<p>Pet: @pet.Name</p>;

    private class Pet
    {
        public string Name { get; set; }
    }
}

Saída renderizada do código anterior:

<p>The time is 4/19/2021 8:54:46 AM.</p>
<p>Pet: Nutty Rex</p>

Ativos estáticos

Blazor segue a convenção dos aplicativos ASP.NET Core para ativos estáticos. Ativos estáticos ficam localizados na pasta web root (wwwroot) ou nas pastas do projeto, sob a pasta wwwroot.

Use um caminho relativo à base (/) para se referir à raiz da Web de um ativo estático. No exemplo a seguir, logo.png está localizado fisicamente na pasta {PROJECT ROOT}/wwwroot/images. {PROJECT ROOT} é a raiz do projeto do aplicativo.

<img alt="Company logo" src="/images/logo.png" />

Os componentes não dão suporte à notação com til e barra (~/).

Para saber como definir o caminho base de um aplicativo, consulte Hospedar e implantar ASP.NET CoreBlazor.

Não há suporte para Auxiliares de Marca nos componentes

Não há suporte para Tag Helpers nos componentes. Para fornecer funcionalidade semelhante à do Auxiliar de Marca em Blazor, crie um componente com a mesma funcionalidade que ele e use o componente em vez disso.

Imagens de gráfico vetorial escalonável (SVG)

Como Blazor renderiza HTML, imagens com suporte de navegador, incluindo imagens SVG (gráficos vetoriais escalonáveis) (.svg), têm suporte por meio da marca <img>:

<img alt="Example image" src="image.svg" />

De maneira semelhante, há suporte para imagens SVG nas regras CSS de um arquivo de folha de estilos (.css):

.element-class {
    background-image: url("image.svg");
}

Blazor dá suporte ao elemento <foreignObject> para exibir HTML arbitrário em um SVG. A marcação pode representar HTML arbitrário, um RenderFragment ou um componente Razor.

O exemplo a seguir demonstra:

  • Exibição de um string (@message).
  • Vinculação bidirecional com um elemento <input> e um campo value.
  • Um componente Robot.
<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">
    <rect x="0" y="0" rx="10" ry="10" width="200" height="200" stroke="black" 
        fill="none" />
    <foreignObject x="20" y="20" width="160" height="160">
        <p>@message</p>
    </foreignObject>
</svg>

<svg xmlns="http://www.w3.org/2000/svg">
    <foreignObject width="200" height="200">
        <label>
            Two-way binding:
            <input @bind="value" @bind:event="oninput" />
        </label>
    </foreignObject>
</svg>

<svg xmlns="http://www.w3.org/2000/svg">
    <foreignObject>
        <Robot />
    </foreignObject>
</svg>

@code {
    private string message = "Lorem ipsum dolor sit amet, consectetur adipiscing " +
        "elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.";

    private string? value;
}

Comportamento de renderização de espaço em branco

A menos que a diretiva @preservewhitespace seja usada com um valor de true, o espaço em branco extra será removido se:

  • Estiver à esquerda ou à direita dentro de um elemento.
  • Estiver à esquerda ou à direita dentro de um parâmetro RenderFragment/RenderFragment<TValue> (por exemplo, conteúdo filho passado para outro componente).
  • Preceder ou seguir um bloco de código C#, como @if ou @foreach.

A remoção do espaço em branco pode afetar a saída renderizada ao usar uma regra de CSS, como white-space: pre. Para desabilitar essa otimização de desempenho e preservar o espaço em branco, execute uma das seguintes ações:

  • Adicione a diretiva @preservewhitespace true na parte superior do arquivo Razor (.razor) para aplicar a preferência a um componente específico.
  • Adicione a diretiva @preservewhitespace true dentro de um arquivo _Imports.razor para aplicar a preferência a um subdiretório ou a todo o projeto.

Na maioria dos casos, nenhuma ação é necessária, pois os aplicativos normalmente continuam se comportando normalmente (mas com mais rapidez). Se a remoção de espaço em branco causar um problema de renderização para um componente específico, use @preservewhitespace true nesse componente para desabilitar essa otimização.

O espaço em branco é mantido na marcação de origem de um componente. O texto somente com espaço em branco é renderizado no DOM do navegador mesmo quando não há nenhum efeito visual.

Considere a seguinte marcação de componente:

<ul>
    @foreach (var item in Items)
    {
        <li>
            @item.Text
        </li>
    }
</ul>

O exemplo anterior renderiza o seguinte espaço em branco desnecessário:

  • Fora do bloco de código @foreach.
  • Ao redor do elemento <li>.
  • Ao redor da saída @item.Text.

Uma lista de 100 itens resulta em mais de 400 áreas de espaço em branco. Nenhum espaço em branco extra afeta visualmente a saída renderizada.

Ao renderizar HTML estático para os componentes, o espaço em branco dentro de uma marca não é preservado. Por exemplo, veja a saída renderizada da seguinte marca <img> em um arquivo Razor do componente (.razor):

<img     alt="Example image"   src="img.png"     />

O espaço em branco não é preservado da marcação anterior:

<img alt="Example image" src="img.png" />

Componente raiz

Um componente Razor raiz (componente raiz) é o primeiro componente carregado de qualquer hierarquia de componentes criada pelo aplicativo.

Em um aplicativo criado a partir do modelo de projeto do Blazor Web App, o componente App (App.razor) é especificado como o componente raiz padrão pelo parâmetro de tipo declarado para a chamada a MapRazorComponents<TRootComponent> no arquivo Program do lado do servidor. O exemplo a seguir mostra o uso do componente App como o componente raiz, que é o padrão para um aplicativo criado a partir do modelo de projeto Blazor:

app.MapRazorComponents<App>();

Observação

Não há suporte para tornar um componente raiz interativo, como o componente App.

Em um aplicativo criado a partir do modelo de projeto Blazor Server, o componente App (App.razor) é especificado como o componente raiz padrão em Pages/_Host.cshtml utilizando o Auxiliar de Marcas de Componentes:

<component type="typeof(App)" render-mode="ServerPrerendered" />

Em um aplicativo criado a partir do modelo de projeto Blazor WebAssembly, o componente App (App.razor) é especificado como o componente raiz padrão no arquivo Program:

builder.RootComponents.Add<App>("#app");

No código anterior, o seletor CSS, #app, indica que o componente App está especificado para o <div> em wwwroot/index.html com um id de app:

<div id="app">...</app>

Os aplicativos MVC e Razor Pages também podem usar o Auxiliar de Marcas de Componente para registrar componentes raiz Blazor WebAssembly renderizados estaticamente:

<component type="typeof(App)" render-mode="WebAssemblyPrerendered" />

Componentes renderizados estaticamente só podem ser adicionados ao aplicativo. Eles não podem ser removidos ou atualizados posteriormente.

Para obter mais informações, consulte os seguintes recursos: