Partilhar via


ASP.NET componentes principais Razor

Observação

Esta não é a versão mais recente deste artigo. Para a versão atual, consulte a versão .NET 9 deste artigo.

Advertência

Esta versão do ASP.NET Core não é mais suportada. Para obter mais informações, consulte a Política de suporte do .NET e .NET Core. Para a versão atual, consulte a versão .NET 9 deste artigo.

Importante

Estas informações referem-se a um produto de pré-lançamento que pode ser substancialmente modificado antes de ser lançado comercialmente. A Microsoft não oferece garantias, expressas ou implícitas, em relação às informações fornecidas aqui.

Para a versão atual, consulte a versão .NET 9 deste artigo.

Este artigo explica como criar e usar componentes Razor em aplicativos Blazor, incluindo orientação sobre sintaxe Razor, nomenclatura de componentes, namespaces e parâmetros de componentes.

Razor componentes

Blazor aplicativos são criados usando componentes Razor, conhecidos informalmente como componentes Blazor ou apenas componentes . Um componente é uma parte independente da interface do usuário (UI) com lógica de processamento para habilitar o 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 DOM (Document Object Model) do navegador chamada de árvore de renderização , que é usada para atualizar a interface do usuário de forma flexível e eficiente.

Embora "Razor components" compartilhe alguns nomes com outras tecnologias de renderização de conteúdo do ASP.NET Core, os componentes Razor devem ser diferenciados das seguintes funcionalidades no ASP.NET Core:

Importante

Ao usar um Blazor Web App, a maioria dos componentes de exemplo de documentação Blazorexige interatividade para funcionar e demonstrar os conceitos cobertos 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 este assunto são fornecidas pelo ASP.NET Core Blazor modos de renderização, 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 C# e marcação HTML nos ficheiros de componente Razor com a extensão de ficheiro .razor.

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

ComponentBase em dotnet/aspnetcore fonte de referência: A fonte de referência contém observações adicionais sobre os eventos integrados do ciclo de vida. No entanto, tenha em mente que as implementações internas de recursos de componentes 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 a ramificação padrão do repositório, que representa o desenvolvimento atual para a próxima versão do .NET. Para selecionar uma tag para uma versão específica, use a lista suspensa Alternar ramificações ou tags. Para obter mais informações, consulte Como selecionar uma marca de versão do código-fonte do ASP.NET Core (dotnet/AspNetCore.Docs #26205).

Os desenvolvedores normalmente criam componentes Razor a partir de arquivos de componentes 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 acionar manualmente a renderização com eventos e métodos de ciclo de vida que o desenvolvedor deve criar e manter.

As convenções adicionais adotadas pelo código de exemplo da documentação e pelos aplicativos de exemplo Blazor são encontradas em Fundamentos do ASP.NET Core Blazor.

Razor sintaxe

Os componentes usam a sintaxe Razor. Dois recursos Razor são amplamente utilizados por componentes: diretivas e atributos de diretiva . Estas são palavras-chave reservadas, prefixadas com @, que aparecem na linguagem de marcação Razor.

  • Diretivas: Alterar a forma como a marcação de componentes é 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 colocadas em uma ordem consistente. Para diretivas repetidas, as diretivas são colocadas alfabeticamente por namespace ou tipo, exceto as diretivas @using, que têm ordenação especial de segundo nível.

    A seguinte ordem é adotada pelos aplicativos de exemplo e pela documentação de exemplo do Blazor. Os componentes fornecidos por um modelo de projeto Blazor podem diferir da seguinte ordem e usar um formato diferente. Por exemplo, os componentes da estrutura BlazorIdentity incluem linhas em branco entre blocos de diretivas @using e blocos de diretivas @inject. Você é livre para usar um esquema de pedidos personalizado e formato em seus próprios aplicativos.

    Documentação e ordem de diretiva Razor para aplicativo de exemplo

    • @page
    • @rendermode (.NET 8 ou posterior)
    • @using
      • System espaços de nomes (ordem alfabética)
      • Microsoft espaços de nomes (ordem alfabética)
      • Namespaces de API de terceiros (ordem alfabética)
      • Namespaces de aplicativos (ordem alfabética)
    • Outras diretivas (ordem alfabética)

    Não aparecem linhas em branco entre as diretivas. Aparece uma linha em branco 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: Muda a maneira como um elemento componente é compilado ou funciona.

    Exemplo:

    <input @bind="episodeId" />
    

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

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

Nome do componente, nome da classe e namespace

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

✔️ suportado:ProductDetail.razor

Não suportado:productDetail.razor

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

  • Caminhos de arquivo e nomes de arquivo usam Pascal case† e aparecem antes de mostrar exemplos de código. Se um caminho estiver presente, ele indica o local típico da pasta. Por exemplo, Components/Pages/ProductDetail.razor indica que o componente ProductDetail tem um nome de arquivo de ProductDetail.razor e reside na pasta Pages da pasta Components do aplicativo.
  • Os caminhos de arquivo de componentes para componentes roteáveis correspondem às suas URLs em kebab case‡ com hífenes aparecendo entre palavras no modelo de rota de um componente. Por exemplo, um componente ProductDetail com um modelo de rota de /product-detail (@page "/product-detail") é solicitado em um navegador na URL relativa /product-detail.

Pascal Case (camel case superior) é uma convenção de nomenclatura sem espaços e pontuação, com a primeira letra de cada palavra em maiúscula, incluindo a primeira palavra.
‡Kebab case é uma convenção de nomenclatura sem espaços e pontuação que usa letras minúsculas e traços entre palavras.

Os componentes são comuns classes C# e podem ser colocados em qualquer lugar dentro de um projeto. Os componentes que produzem páginas da Web geralmente residem na pasta Components/Pages. Os componentes que não são de página são frequentemente 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 do local do componente (pasta) dentro do aplicativo. Se o namespace raiz do aplicativo estiver BlazorSample e o componente Counter residir na pasta Components/Pages:

  • O namespace do componente Counter é BlazorSample.Components.Pages.
  • O nome do tipo totalmente qualificado do componente é 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 exemplo a seguir disponibiliza componentes na pasta AdminComponents:

@using BlazorSample.AdminComponents

Observação

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

É oferecido suporte para declarações using com alias. No exemplo a seguir, a classe de WeatherForecast pública do componente GridRendering é disponibilizada como WeatherForecast em um componente em outro lugar no aplicativo:

@using WeatherForecast = Components.Pages.GridRendering.WeatherForecast

Os componentes também podem ser referenciados usando seus nomes totalmente qualificados, o que não requer uma diretiva @using. O exemplo a seguir 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 baseia-se no seguinte (em ordem de prioridade):

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

Os seguintes não são suportados :

  • A qualificação global::.
  • Nomes parcialmente qualificados. Por exemplo, não é possível adicionar @using BlazorSample.Components a um componente e, em seguida, fazer referência ao componente NavMenu na pasta Components/Layout do aplicativo (Components/Layout/NavMenu.razor) com <Layout.NavMenu></Layout.NavMenu>.

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

✔️ suportado:ProductDetail.razor

Não suportado:productDetail.razor

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

  • Caminhos de arquivo e nomes de arquivo usam Pascal case† e aparecem antes de mostrar exemplos de código. Se um caminho estiver presente, ele indica o local típico da pasta. Por exemplo, Pages/ProductDetail.razor indica que o componente ProductDetail tem um nome de arquivo de ProductDetail.razor e reside na pasta Pages do aplicativo.
  • Os caminhos de arquivo de componentes para componentes roteáveis correspondem às suas URLs em kebab case‡ com hífenes aparecendo entre palavras no modelo de rota de um componente. Por exemplo, um componente ProductDetail com um modelo de rota de /product-detail (@page "/product-detail") é solicitado em um navegador na URL relativa /product-detail.

Pascal Case (camel case superior) é uma convenção de nomenclatura sem espaços e pontuação, com a primeira letra de cada palavra em maiúscula, incluindo a primeira palavra.
‡Kebab case é uma convenção de nomenclatura sem espaços e pontuação que usa letras minúsculas e traços entre palavras.

Os componentes são comuns classes C# e podem ser colocados em qualquer lugar dentro de um projeto. Os componentes que produzem páginas da Web geralmente residem na pasta Pages. Os componentes que não são de página são frequentemente 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 do local do componente (pasta) dentro do aplicativo. Se o namespace raiz do aplicativo estiver BlazorSample e o componente Counter residir na pasta Pages:

  • O namespace do componente Counter é BlazorSample.Pages.
  • O nome do tipo totalmente qualificado do componente é 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 exemplo a seguir disponibiliza componentes na pasta AdminComponents:

@using BlazorSample.AdminComponents

Observação

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

É oferecido suporte para declarações using com alias. No exemplo a seguir, a classe de WeatherForecast pública do componente GridRendering é disponibilizada como WeatherForecast em um componente em outro lugar no aplicativo:

@using WeatherForecast = Pages.GridRendering.WeatherForecast

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

<BlazorSample.Components.ProductDetail />

O namespace de um componente criado com Razor baseia-se no seguinte (em ordem de prioridade):

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

Os seguintes não são suportados :

  • A qualificação global::.
  • Nomes parcialmente qualificados. Por exemplo, não é possível adicionar @using BlazorSample a um componente e, em seguida, fazer referência ao componente NavMenu na pasta Shared do aplicativo (Shared/NavMenu.razor) com <Shared.NavMenu></Shared.NavMenu>.

Suporte parcial de classe

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

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

Observação

Uma folha de estilo de componente que define estilos específicos de componentes é um arquivo separado (.css). Blazor isolamento CSS é descrito posteriormente em ASP.NET isolamento CSS do Core Blazor.

O exemplo a seguir mostra o componente Counter padrão com um bloco @code em um aplicativo gerado a partir de um modelo de projeto Blazor. A marcação e o código C# estão no mesmo arquivo. Esta é 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"

<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 o HTML de apresentação e a marcação Razor do código C#, através de um ficheiro code-behind com uma classe parcial. A divisão da marcação do código C# é favorecida por algumas organizações e desenvolvedores para organizar seu código de 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 trabalhando na lógica C# do componente. A abordagem também é útil ao trabalhar com código gerado automaticamente ou geradores de código-fonte. Para obter mais informações, consulte classes e métodos parciais (Guia de programação em 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"

<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.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++;
        }
    }
}

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

Namespaces típicos usados por 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;

Os 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;

Os 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;

Os 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. Diferente do uso de classes parciais, que apenas dividem a marcação da lógica C#, usar uma classe base permite herdar código C# a utilizar num grupo de componentes que partilham as propriedades e métodos da classe base. O uso de classes base reduz a redundância de código em aplicativos e é útil ao fornecer código base de bibliotecas de classes para vários aplicativos. Para obter mais informações, consulte 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

<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!";
}
using Microsoft.AspNetCore.Components;

namespace BlazorSample;

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

Roteamento

O roteamento em Blazor é obtido 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 de rota. No tempo de execução, o roteador procura classes de componentes com um RouteAttribute e renderiza qualquer componente que tenha um modelo de rota que corresponda à URL solicitada.

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

HelloWorld.razor:

@page "/hello-world"

<PageTitle>Hello World!</PageTitle>

<h1>Hello World!</h1>
@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 na posição /hello-world, independentemente de se adicionar ou não o componente à navegação da interface do utilizador da aplicação. Opcionalmente, os componentes podem ser adicionados ao componente NavMenu para que um link para o componente apareça na navegação baseada na 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 ASP.NET Core Blazor de roteação e navegação.

Marcação

A UI (interface do utilizador) de um componente é definida usando a sintaxe Razor, que consiste em Razor marcação, C# e HTML. Quando um aplicativo é compilado, a marcação HTML e a lógica de renderização 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. Em blocos @code, o estado do componente é especificado e processado com C#:

  • Inicializadores de propriedade e campo.
  • Valores dos parâmetros a partir dos argumentos passados pelos componentes pai e dos parâmetros de rota.
  • Métodos para manipulação de eventos do usuário, eventos do ciclo de vida e lógica de componentes personalizados.

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

  • headingFontStyle para o valor da propriedade CSS font-style do elemento de cabeçalho.
  • headingText para o conteúdo do elemento cabeçalho.

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"

<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 em toda a documentação Blazor especificam o private modificador de acesso para membros privados. Os membros privados estão limitados ao âmbito da classe de um componente. No entanto, o C# assume o modificador de acesso private quando nenhum modificador de acesso está presente, portanto, marcar explicitamente os membros "private" em seu próprio código é opcional. Para obter mais informações sobre modificadores de acesso, consulte Access Modifiers (C# Programming Guide).

A estrutura Blazor processa um componente internamente como uma árvore de renderização , que é a combinação do DOM de um componente e Cascading Style Sheet Object Model (CSSOM). Depois que o componente é inicialmente renderizado, a árvore de renderização do componente é regenerada em resposta a eventos. Blazor compara a nova árvore de renderização com a árvore de renderização anterior e aplica quaisquer modificações ao DOM do navegador para exibição. Para obter mais informações, consulte Razor.

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

Os métodos assíncronos (async) não suportam o retorno de void

A estrutura Blazor não monitoriza métodos assíncronos que retornam void(async). Como resultado, as exceções não são detetadas se void for devolvida. Sempre retorne um Task nos métodos assíncronos.

Componentes aninhados

Os componentes podem incluir outros componentes declarando-os usando sintaxe HTML. A marcação para usar um componente se parece com uma tag HTML onde o nome da tag é o tipo de componente.

Considere o seguinte componente Heading, que pode ser usado por outros componentes para exibir um cabeçalho.

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";
}
<h1 style="font-style:@headingFontStyle">Heading Example</h1>

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

A seguinte marcação no componente HeadingExample renderiza o componente Heading anterior no local onde a etiqueta <Heading /> aparece.

HeadingExample.razor:

@page "/heading-example"

<PageTitle>Heading</PageTitle>

<h1>Heading Example</h1>

<Heading />
@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 corresponda a um nome de componente dentro do mesmo namespace, um aviso será emitido indicando que o elemento tem um nome inesperado. Adicionar uma diretiva @using para o namespace do componente torna o componente disponível, o que resolve o aviso. Para obter mais informações, consulte a seção Nome do componente, nome da classe e do namespace.

O exemplo de componente 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 noutro componente. Se o componente Heading fosse diretamente acessível ao incluir @page "/heading" no topo do seu arquivo de Razor, então o componente seria renderizado para requisições do navegador tanto em /heading quanto em /heading-example.

Parâmetros dos componentes

Os parâmetros de componente passam dados para os componentes e são definidos usando propriedades públicas C# na classe de componente com o atributo [Parameter].

No seguinte componente ParameterChild, os parâmetros do componente incluem:

  • Tipos de referência incorporados.

  • Um tipo de referência definido pelo usuário (PanelBody) para passar um corpo de cartão Bootstrap no Body.

    PanelBody.cs:

    namespace BlazorSample;
    
    public class PanelBody
    {
        public string? Text { get; set; }
        public string? Style { get; set; }
    }
    
    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">
        <p>@Body.Text</p>
        @if (Count is not null)
        {
            <p>The count is @Count.</p>
        }
    </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"
        };

    [Parameter]
    public int? Count { get; set; }
}
<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">
        <p>@Body.Text</p>
        @if (Count is not null)
        {
            <p>The count is @Count.</p>
        }
    </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"
        };
    
    [Parameter]
    public int? Count { get; set; }
}
<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">
        <p>@Body.Text</p>
        @if (Count is not null)
        {
            <p>The count is @Count.</p>
        }
    </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"
        };

    [Parameter]
    public int? Count { get; set; }
}
<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">
        <p>@Body.Text</p>
        @if (Count is not null)
        {
            <p>The count is @Count.</p>
        }
    </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"
        };

    [Parameter]
    public int? Count { get; set; }
}
<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">
        <p>@Body.Text</p>
        @if (Count is not null)
        {
            <p>The count is @Count.</p>
        }
    </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"
        };

    [Parameter]
    public int? Count { get; set; }
}
<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">
        <p>@Body.Text</p>
        @if (Count is not null)
        {
            <p>The count is @Count.</p>
        }
    </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"
        };

    [Parameter]
    public int? Count { get; set; }
}

Advertência

Há suporte para o fornecimento de valores iniciais para parâmetros de componentes, mas não crie um componente que grave em seus próprios parâmetros depois que o componente for renderizado pela primeira vez. Para obter mais informações, consulte Evitar o sobrescrever de parâmetros no ASP.NET Core Blazor.

Os parâmetros do componente ParameterChild podem ser definidos através de argumentos na tag HTML que renderiza uma instância do componente ParameterChild. O seguinte componente principal renderiza dois componentes ParameterChild:

  • O primeiro componente ParameterChild é renderizado sem fornecer argumentos de parâmetro.
  • O segundo componente ParameterChild recebe valores para Title e Body do componente pai, que usa uma expressão C# explícita para definir os valores das propriedades do 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" })" />

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 a seguir, renderizada pelo componente pai, mostra os valores padrão do componente ParameterChild quando não há fornecimento de valores de parâmetro pelo componente pai. Quando o componente pai fornece valores de parâmetro, estes substituem os valores padrão do componente ParameterChild.

Observação

Para maior clareza, a maioria das classes de estilo CSS renderizadas e alguns elementos não são mostrados na marcação HTML renderizada a seguir. O conceito principal demonstrado pelo exemplo a seguir é que o componente pai atribuiu valores ao componente filho usando seus parâmetros de componente.

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

<div>Set By Child</div>
<div style="font-style:normal">
    <p>Card content set by child.</p>
</div>

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

<div>Set by Parent</div>
<div style="font-style:italic">
    <p>Set by parent.</p>
</div>

Atribua um campo, propriedade ou 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 é obrigatório.

Se o parâmetro do componente for do tipo string, 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 componente pai a seguir exibe quatro instâncias do componente ParameterChild anterior e define seus valores de parâmetro Title para:

  • 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 .
  • A propriedade panelData do objeto Title.

A quinta instância do componente ParameterChild também define o parâmetro Count. Note como um parâmetro do tipo stringrequer um prefixo @ para garantir que uma expressão não seja tratada como um literal de string. No entanto, Count é um inteiro anulável (System.Int32), de modo que Count pode receber o valor de count sem um prefixo @. Você pode estabelecer uma convenção de código alternativa que exija que os desenvolvedores em sua organização sempre prefixem com @. De qualquer forma, recomendamos apenas que adote uma abordagem consistente para a forma como os parâmetros do componente são passados no código Razor.

As citações em torno dos valores dos atributos de parâmetro são opcionais na maioria dos casos de acordo com a especificação HTML5. Por exemplo, Value=this é suportado, em vez de Value="this". No entanto, recomendamos o uso de aspas porque é mais fácil de lembrar e amplamente adotado em tecnologias baseadas na web.

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

  • Use sempre aspas. Exemplo: Value="this".
  • Não use o prefixo @ com não literais, exceto quando necessário. Exemplo: Count="count", onde count é uma variável digitada por número. Count="@count" é uma abordagem estilística válida, mas a documentação e os exemplos não adotam a convenção.
  • Sempre evite 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 suportado.

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" />

<ParameterChild Title="String literal title" Count="count" />

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

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

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

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" />

<ParameterChild Title="String literal title" Count="count" />

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

    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" />

<ParameterChild Title="String literal title" Count="count" />

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

    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" />

<ParameterChild Title="String literal title" Count="count" />

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

    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" />

<ParameterChild Title="String literal title" Count="count" />

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

    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 componente, não prefixe o atributo HTML do parâmetro com @.

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

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

Incorreto:

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

Ao contrário de Razor páginas (.cshtml), Blazor não pode executar trabalho assíncrono numa expressão Razor ao renderizar um componente. Isso ocorre porque Blazor foi projetado para renderizar interfaces do usuário interativas. Em uma interface do usuário interativa, a tela sempre deve exibir algo, portanto, não faz sentido bloquear o fluxo de renderização. Em vez disso, o trabalho assíncrono é executado durante um dos eventos assíncronos do ciclo de vida . Após cada evento de ciclo de vida assíncrono, o componente pode renderizar novamente. A sintaxe Razor a seguir não é suportada:

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

O código no exemplo anterior gera um de 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 forma assíncrona, o componente pode usar o OnInitializedAsync evento de ciclo de vida, como demonstra o exemplo a seguir:

<ParameterChild Title="@title" />

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

Para obter mais informações, consulte o ciclo de vida do componente ASP.NET Core Razor.

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 não é suportado. O exemplo a seguir procura concatenar o texto "Set by " com o valor da propriedade de um objeto. Embora esta sintaxe seja suportada numa página de Razor (.cshtml), ela não é válida para atribuição do parâmetro Title ao filho num componente. A sintaxe Razor a seguir não é suportada:

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

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

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

Para dar suporte à atribuição de um valor composto, use um método, campo ou propriedade. O exemplo a seguir realiza 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";
    }
}

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 Razor referência de sintaxe para ASP.NET Core.

Advertência

Há suporte para o fornecimento de valores iniciais para parâmetros de componentes, mas não crie um componente que grave em seus próprios parâmetros depois que o componente for renderizado pela primeira vez. Para obter mais informações, consulte Evitar o sobrescrever de parâmetros no ASP.NET Core Blazor.

Os parâmetros do componente devem ser declarados como propriedades automáticas , o que significa que eles não devem conter lógica personalizada nos seus acessores 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 dos componentes têm como único propósito servir de canal para um componente pai transferir informações para um componente filho. Se um acessador set de uma propriedade de um componente filho contiver lógica que cause a rerenderização do componente pai, resultará num loop de renderização infinito.

Para transformar um valor de parâmetro recebido:

  • Deixe a propriedade parameter 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 cada vez que novos dados são recebidos.

A gravação de um valor inicial em um parâmetro de componente é suportada porque as atribuições de valor inicial não interferem com a renderização automática de componentes do Blazor. A seguinte atribuição do DateTime local atual com DateTime.Now para StartData é 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 atribuir um valor a StartData no código do desenvolvedor. Para obter mais informações, consulte Evitar o sobrescrever 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, os editores ou ferramentas de compilação poderão exibir avisos para o usuário. Este atributo só é válido em propriedades também marcadas com o atributo [Parameter]. O EditorRequiredAttribute é imposto em tempo de design e quando a aplicação é criada. O atributo não é imposto em tempo de execução e não garante um valor de parâmetro nãonull.

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

Listas de atributos de linha única também são suportadas:

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

Não use o modificador required ou ou o acessador init ou nas propriedades dos parâmetros do componente. Os componentes são geralmente instanciados e têm valores de parâmetros atribuídos usando reflexão , o que ignora as garantias que init e required são destinados a assegurar. Em vez disso, use o atributo [EditorRequired] para especificar um parâmetro de componente necessário.

Não utilize o acessador init nas propriedades dos parâmetros do componente, pois a definição dos valores dos parâmetros do componente com ParameterView.SetParameterProperties utiliza a reflexão , o que contorna a restrição do setter de inicialização apenas. Use o atributo [EditorRequired] para especificar um parâmetro de componente necessário.

Não utilize o acessador init nas propriedades dos parâmetros do componente, pois a definição dos valores dos parâmetros do componente com ParameterView.SetParameterProperties utiliza a reflexão , o que contorna a restrição do setter de inicialização apenas.

Tuples (documentação da API) é suportado para parâmetros de componentes e tipos RenderFragment. O exemplo de parâmetro de componente a seguir passa três valores em 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);
}

Há suporte para tuplas nomeadas, como mostrado 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);
}

Citação ©2005 Universal Pictures: Serenity (Nathan Fillion)

Tuples (documentação da API) é suportado para parâmetros de componentes e tipos RenderFragment. O exemplo de parâmetro de componente a seguir passa três valores em 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);
}

Há suporte para tuplas nomeadas, como mostrado 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);
}

Citação ©2005 Universal Pictures: Serenity (Nathan Fillion)

Tuples (documentação da API) é suportado para parâmetros de componentes e tipos RenderFragment. O exemplo de parâmetro de componente a seguir passa três valores em 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);
}

Há suporte para tuplas nomeadas, como mostrado 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);
}

Citação ©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 utiliza parâmetros de rota para preencher os parâmetros de componentes 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}"

<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, consulte a seção Parâmetros de rota do Blazorde roteamento e navegação do Core . Parâmetros de rota opcionais também são suportados e abordados na mesma seção. Para obter informações sobre parâmetros de rota catch-all ({*pageRoute}), que capturam caminhos através de vários limites de pasta, consulte a seção Catch-all route parameters do ASP.NET Core Blazor roteamento e navegação.

Para obter mais informações, consulte a seção Parâmetros de rota do Blazorde roteamento e navegação do Core . Não há suporte para parâmetros de rota opcionais, portanto, duas diretivas @page são necessárias (consulte a seção Parâmetros de rota para obter mais informações). Para obter informações sobre parâmetros de rota catch-all ({*pageRoute}), que capturam caminhos através de vários limites de pasta, consulte a seção Catch-all route parameters do ASP.NET Core Blazor roteamento e navegação.

Advertência

Com a compactação, que é 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 interoperabilidade 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 BlazorSignalR guidance e Threat mitigation guidance for ASP.NET Core Blazor renderização interativa do lado do servidor.

Fragmentos para 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 tags 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 na marcação Razor do componente é 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; }
}
<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.

As funções de retorno de eventos não são suportadas para RenderFragment.

O componente a seguir fornece conteúdo para renderizar o RenderFragmentChild colocando o conteúdo dentro das tags 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>

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 apresentar conteúdo filho em aplicações Blazor e são descritos com exemplos nos seguintes artigos e secções de artigos:

Observação

Blazor Os componentes internos incorporados da estrutura de Razor usam a mesma convenção de parâmetros de componente para definir seus conteúdos ChildContent. Você pode ver os componentes que definem o conteúdo filho ao pesquisar pelo nome da propriedade do parâmetro do componente ChildContent na documentação da API do (filtrando a API com o termo de pesquisa "ChildContent").

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

Você pode destacar 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 mais informações, consulte Reutilização da lógica de renderização.

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

A renderização de componentes dentro de um loop for requer uma variável de índice local se a variável de incremento do ciclo for usada pelos parâmetros do componente ou conteúdo filho de RenderFragment.

Considere o seguinte componente RenderFragmentChild2 que tem um parâmetro de componente (Id) e um fragmento de apresentação para exibir 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 de foreach com Enumerable.Range em vez de um loop de for:

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

Capturar referências a componentes

As referências de componente fornecem uma maneira de fazer referência a uma instância de componente para emitir comandos. Para capturar uma referência de componente:

  • Adicione um atributo @ref ao componente filho.
  • Defina um campo com o mesmo tipo do 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 seguinte componente ReferenceChild 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();
    }
}
@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 após a renderização do componente e que a sua saída inclui o elemento de ReferenceChild. Até que o componente seja renderizado, não há nada para referência. Não tente chamar um método de componente referenciado para um manipulador de eventos diretamente (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 click é atribuído.

Para manipular referências de componentes depois que o componente terminar a renderização, use os métodos OnAfterRender ou OnAfterRenderAsync.

O exemplo a seguir usa o componente ReferenceChild 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);
    }
}
@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 à captura de referências de elementos, a captura de referências de componentes não é um recurso de interoperabilidade JavaScript. As referências de componentes não são passadas para o código JavaScript. As referências de componentes são usadas apenas no código .NET.

Importante

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

Aplicar um atributo

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

@page "/"
@attribute [Authorize]

Atributos de elemento HTML condicional e propriedades DOM

Blazor adota os seguintes comportamentos gerais:

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

Quais Razor atributos de sintaxe correspondem a atributos HTML e quais correspondem a propriedades DOM permanece não documentado porque este é um detalhe de implementação da estrutura que pode ser alterado sem aviso prévio.

Advertência

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

HTML bruto

As cadeias de caracteres são normalmente 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, envolva o conteúdo HTML em um valor MarkupString. O valor é analisado como HTML ou SVG e inserido no DOM.

Advertência

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

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>";
}

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>";
}

Razor modelos

Os fragmentos de renderização podem ser definidos usando a sintaxe de 'template' Razor para definir um trecho da interface de utilizador. Razor modelos usam o seguinte formato:

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

O exemplo a seguir ilustra como especificar RenderFragment e RenderFragment<TValue> valores e renderizar modelos diretamente em um componente. Os 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"

<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 de aplicativos ASP.NET Core para ativos estáticos. Os ativos estáticos estão localizados na pasta web root (wwwroot) do projeto ou pastas 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á fisicamente localizado 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 suportam notação tilde-slash (~/).

Para obter informações sobre como definir o caminho base de um aplicativo, consulte Host e implantar ASP.NET Core Blazor.

Os Ajudantes de Tags não são suportados nos componentes

Tag Helpers não são suportados em componentes. Para fornecer funcionalidade semelhante ao Auxiliar de Tag no Blazor, crie um componente com a mesma funcionalidade do Auxiliar de Tag e use o componente em vez disso.

Imagens de Gráficos Vetoriais Escaláveis (SVG)

Como o Blazor renderiza HTML, as imagens suportadas pelo navegador, incluindo imagens Scalable Vetor Graphics (SVG) (.svg), são suportadas por meio da tag <img>:

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

Da mesma forma, as imagens SVG são suportadas nas regras CSS de um arquivo de folha de estilo (.css):

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

Blazor suporta o elemento <foreignObject> para exibir HTML arbitrário dentro de um SVG. A marcação pode representar HTML arbitrário, um RenderFragmentou um componente Razor.

O exemplo a seguir demonstra:

  • Exibição de um string (@message).
  • Ligaçã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:

  • À frente ou à direita dentro de um elemento.
  • No início ou no fim dentro de um parâmetro RenderFragment/RenderFragment<TValue> (por exemplo, conteúdo filho passado para outro componente).
  • Ele precede ou segue um bloco de código C#, como @if ou @foreach.

A remoção de espaço em branco pode afetar a saída renderizada ao usar uma regra CSS, como white-space: pre. Para desativar 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 de 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 a se comportar normalmente (mas mais rápido). 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 é retido 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á 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.
  • Em torno do elemento <li>.
  • Em torno da saída @item.Text.

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

Ao renderizar HTML estático para componentes, o espaço em branco dentro de uma tag não é preservado. Por exemplo, visualize a saída renderizada da seguinte tag <img> num arquivo componente Razor (.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 de Razor raiz (componente raiz) é o primeiro componente carregado de qualquer hierarquia de componentes criada pela aplicação.

Em um aplicativo criado a partir do modelo de projeto Blazor Web App, o componente App (App.razor) é especificado como o componente raiz padrão pelo parâmetro type declarado para a chamada para 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 usando o Component Tag Helper:

<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 Component Tag Helper para registrar componentes raiz Blazor WebAssembly renderizados estaticamente:

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

Os 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:

IHttpContextAccessor/HttpContext

IHttpContextAccessor geralmente deve ser evitado com a renderização interativa porque um HttpContext válido nem sempre está disponível.

IHttpContextAccessor pode ser usado para componentes que são renderizados estaticamente no servidor. No entanto, recomendamos evitá-lo, se possível.

HttpContext pode ser usado como um parâmetro em cascata somente em componentes raiz renderizados estaticamente para tarefas gerais, como inspecionar e modificar cabeçalhos ou outras propriedades no componente App (Components/App.razor). O valor é sempre null para renderização interativa.

[CascadingParameter]
public HttpContext? HttpContext { get; set; }

Para cenários em que o HttpContext é necessário em componentes interativos, recomendamos transferir os dados através do estado persistente do componente do servidor. Para obter mais informações, consulte ASP.NET Core do lado do servidor e Blazor Web App cenários de segurança adicionais.

Não use IHttpContextAccessor/HttpContext direta ou indiretamente nos componentes Razor de aplicativos Blazor do lado do servidor. Blazor aplicativos são executados fora do contexto de pipeline do ASP.NET Core. Não é garantido que o HttpContext esteja disponível no IHttpContextAccessore não é garantido que HttpContext mantenha o contexto que iniciou o aplicativo Blazor.

A abordagem recomendada para passar o estado da solicitação para o aplicativo Blazor é por meio de parâmetros de componente raiz durante a renderização inicial do aplicativo. Como alternativa, a aplicação pode copiar os dados para um serviço com escopo no evento do ciclo de vida de inicialização do componente raiz para uso em toda a aplicação. Para obter mais informações, consulte ASP.NET Core do lado do servidor e Blazor Web App cenários de segurança adicionais.

Um aspeto crítico da segurança Blazor do lado do servidor é que o utilizador associado a um determinado circuito pode ser atualizado em algum momento depois que o circuito Blazor é estabelecido, mas o IHttpContextAccessornão é atualizado. Para mais informações sobre como abordar esta situação com serviços personalizados, consulte ASP.NET Core no lado do servidor e Blazor Web App cenários adicionais de segurança.