Criar e usar ASP.NET Core componentes do RazorCreate and use ASP.NET Core Razor components

De Luke Latham e Daniel RothBy Luke Latham and Daniel Roth

Exibir ou baixar código de exemplo (como baixar)View or download sample code (how to download)

Blazor aplicativos são criados usando componentes. apps are built using components. Um componente é uma parte independente da interface do usuário (IU), como uma página, uma caixa de diálogo ou um formulário.A component is a self-contained chunk of user interface (UI), such as a page, dialog, or form. Um componente inclui marcação HTML e a lógica de processamento necessária para injetar dados ou responder a eventos da interface do usuário.A component includes HTML markup and the processing logic required to inject data or respond to UI events. Os componentes são flexíveis e leves.Components are flexible and lightweight. Eles podem ser aninhados, reutilizados e compartilhados entre projetos.They can be nested, reused, and shared among projects.

Classes de componenteComponent classes

Os componentes são implementados em arquivos de componente do Razor ( . Razor) C# usando uma combinação de marcação HTML e.Components are implemented in Razor component files (.razor) using a combination of C# and HTML markup. Um componente no Blazor é formalmente referido como um componente Razor.A component in Blazor is formally referred to as a Razor component.

O nome de um componente deve começar com um caractere maiúsculo.A component's name must start with an uppercase character. Por exemplo, MyCoolComponent. Razor é válido e MyCoolComponent. Razor é inválido.For example, MyCoolComponent.razor is valid, and myCoolComponent.razor is invalid.

A interface do usuário para um componente é definida usando HTML.The UI for a component is defined using HTML. A lógica de renderização dinâmica (por exemplo, loops, condicionais, expressões) é adicionada usando uma sintaxe de C# inserida chamada Razor.Dynamic rendering logic (for example, loops, conditionals, expressions) is added using an embedded C# syntax called Razor. Quando um aplicativo é compilado, a marcação HTML e C# a lógica de renderização são convertidas em uma classe de componente.When an app is compiled, the HTML markup and C# rendering logic are converted into a component class. O nome da classe gerada corresponde ao nome do arquivo.The name of the generated class matches the name of the file.

Os membros da classe de componente são definidos em um bloco @code.Members of the component class are defined in an @code block. No bloco de @code, estado do componente (Propriedades, campos) é especificado com métodos para manipulação de eventos ou para definir outra lógica de componente.In the @code block, component state (properties, fields) is specified with methods for event handling or for defining other component logic. Mais de um bloco de @code é permitido.More than one @code block is permissible.

Observação

Nas visualizações anteriores do ASP.NET Core 3,0, os blocos de @functions foram usados para a mesma finalidade que os blocos de @code nos componentes do Razor.In prior previews of ASP.NET Core 3.0, @functions blocks were used for the same purpose as @code blocks in Razor components. os blocos de @functions continuam a funcionar em componentes do Razor, mas é recomendável usar o bloco de @code no ASP.NET Core 3,0 Preview 6 ou posterior.@functions blocks continue to function in Razor components, but we recommend using the @code block in ASP.NET Core 3.0 Preview 6 or later.

Os membros do componente podem ser usados como parte da lógica de renderização do C# componente usando expressões que começam com @.Component members can be used as part of the component's rendering logic using C# expressions that start with @. Por exemplo, um C# campo é renderizado pela prefixação @ ao nome do campo.For example, a C# field is rendered by prefixing @ to the field name. O exemplo a seguir avalia e renderiza:The following example evaluates and renders:

  • _headingFontStyle ao valor da propriedade CSS para font-style._headingFontStyle to the CSS property value for font-style.
  • _headingText o conteúdo do elemento <h1>._headingText to the content of the <h1> element.
<h1 style="font-style:@_headingFontStyle">@_headingText</h1>

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

Depois que o componente é processado inicialmente, o componente regenera sua árvore de renderização em resposta a eventos.After the component is initially rendered, the component regenerates its render tree in response to events. em seguida, Blazor compara a nova árvore de renderização com a anterior e aplica quaisquer modificações à Modelo de Objeto do Documento do navegador (DOM).Blazor then compares the new render tree against the previous one and applies any modifications to the browser's Document Object Model (DOM).

Os componentes são C# classes comuns e podem ser colocados em qualquer lugar dentro de um projeto.Components are ordinary C# classes and can be placed anywhere within a project. Os componentes que produzem páginas da Web geralmente residem na pasta páginas .Components that produce webpages usually reside in the Pages folder. Os componentes que não são de página são frequentemente colocados na pasta compartilhada ou em uma pasta personalizada adicionada ao projeto.Non-page components are frequently placed in the Shared folder or a custom folder added to the project. Para usar uma pasta personalizada, adicione o namespace da pasta personalizada ao componente pai ou ao arquivo _Imports. Razor do aplicativo.To use a custom folder, add the custom folder's namespace to either the parent component or to the app's _Imports.razor file. Por exemplo, o namespace a seguir torna os componentes em uma pasta componentes disponíveis quando o namespace raiz do aplicativo é WebApplication:For example, the following namespace makes components in a Components folder available when the app's root namespace is WebApplication:

@using WebApplication.Components

Integrar componentes em aplicativos Razor Pages e MVCIntegrate components into Razor Pages and MVC apps

Use componentes com os aplicativos Razor Pages e MVC existentes.Use components with existing Razor Pages and MVC apps. Não é necessário reescrever páginas ou exibições existentes para usar os componentes do Razor.There's no need to rewrite existing pages or views to use Razor components. Quando a página ou a exibição é renderizada, os componentes são renderizados ao mesmo tempo.When the page or view is rendered, components are prerendered at the same time.

Para renderizar um componente de uma página ou exibição, use o Component o auxiliar de marca:To render a component from a page or view, use the Component Tag Helper:

<component type="typeof(Counter)" render-mode="ServerPrerendered" 
    param-IncrementAmount="10" />

Há suporte para a passagem de parâmetros (por exemplo, IncrementAmount no exemplo anterior).Passing parameters (for example, IncrementAmount in the preceding example) is supported.

RenderMode configura se o componente:RenderMode configures whether the component:

  • É renderizado na página.Is prerendered into the page.
  • É renderizado como HTML estático na página ou se inclui as informações necessárias para inicializar um aplicativo Blazor do agente do usuário.Is rendered as static HTML on the page or if it includes the necessary information to bootstrap a Blazor app from the user agent.
RenderMode DescriçãoDescription
ServerPrerendered Renderiza o componente em HTML estático e inclui um marcador para um aplicativo do Blazor Server.Renders the component into static HTML and includes a marker for a Blazor Server app. Quando o agente do usuário é iniciado, esse marcador é usado para inicializar um aplicativo Blazor.When the user-agent starts, this marker is used to bootstrap a Blazor app.
Server Renderiza um marcador para um aplicativo do Blazor Server.Renders a marker for a Blazor Server app. A saída do componente não está incluída.Output from the component isn't included. Quando o agente do usuário é iniciado, esse marcador é usado para inicializar um aplicativo Blazor.When the user-agent starts, this marker is used to bootstrap a Blazor app.
Static Renderiza o componente em HTML estático.Renders the component into static HTML.

Embora as páginas e exibições possam usar componentes, o inverso não é verdadeiro.While pages and views can use components, the converse isn't true. Os componentes não podem usar cenários específicos de exibição e de página, como exibições parciais e seções.Components can't use view- and page-specific scenarios, such as partial views and sections. Para usar a lógica da exibição parcial em um componente, desfatore a lógica de exibição parcial em um componente.To use logic from partial view in a component, factor out the partial view logic into a component.

Não há suporte para a renderização de componentes de servidor de uma página HTML estática.Rendering server components from a static HTML page isn't supported.

Para obter mais informações sobre como os componentes são renderizados, estado do componente e o auxiliar de marca de Component, consulte Modelos de Hospedagem de Blazor ASP.NET Core.For more information on how components are rendered, component state, and the Component Tag Helper, see Modelos de Hospedagem de Blazor ASP.NET Core.

Para renderizar um componente de uma página ou exibição, use o RenderComponentAsync<TComponent> método auxiliar HTML:To render a component from a page or view, use the RenderComponentAsync<TComponent> HTML helper method:

@(await Html.RenderComponentAsync<MyComponent>(RenderMode.ServerPrerendered))

RenderMode configura se o componente:RenderMode configures whether the component:

  • É renderizado na página.Is prerendered into the page.
  • É renderizado como HTML estático na página ou se inclui as informações necessárias para inicializar um aplicativo Blazor do agente do usuário.Is rendered as static HTML on the page or if it includes the necessary information to bootstrap a Blazor app from the user agent.
RenderMode DescriçãoDescription
ServerPrerendered Renderiza o componente em HTML estático e inclui um marcador para um aplicativo do Blazor Server.Renders the component into static HTML and includes a marker for a Blazor Server app. Quando o agente do usuário é iniciado, esse marcador é usado para inicializar um aplicativo Blazor.When the user-agent starts, this marker is used to bootstrap a Blazor app. Não há suporte para parâmetros.Parameters aren't supported.
Server Renderiza um marcador para um aplicativo do Blazor Server.Renders a marker for a Blazor Server app. A saída do componente não está incluída.Output from the component isn't included. Quando o agente do usuário é iniciado, esse marcador é usado para inicializar um aplicativo Blazor.When the user-agent starts, this marker is used to bootstrap a Blazor app. Não há suporte para parâmetros.Parameters aren't supported.
Static Renderiza o componente em HTML estático.Renders the component into static HTML. Há suporte para os parâmetros.Parameters are supported.

Embora as páginas e exibições possam usar componentes, o inverso não é verdadeiro.While pages and views can use components, the converse isn't true. Os componentes não podem usar cenários específicos de exibição e de página, como exibições parciais e seções.Components can't use view- and page-specific scenarios, such as partial views and sections. Para usar a lógica da exibição parcial em um componente, desfatore a lógica de exibição parcial em um componente.To use logic from partial view in a component, factor out the partial view logic into a component.

Não há suporte para a renderização de componentes de servidor de uma página HTML estática.Rendering server components from a static HTML page isn't supported.

Para obter mais informações sobre como os componentes são renderizados, o estado do componente e o RenderComponentAsync auxiliar HTML, consulte Modelos de Hospedagem de Blazor ASP.NET Core.For more information on how components are rendered, component state, and the RenderComponentAsync HTML Helper, see Modelos de Hospedagem de Blazor ASP.NET Core.

Usar componentesUse components

Os componentes podem incluir outros componentes, declarando-os usando a sintaxe do elemento HTML.Components can include other components by declaring them using HTML element syntax. A marcação para uso de um componente é semelhante a uma marca HTML, em que o nome da marca é o tipo de componente.The markup for using a component looks like an HTML tag where the name of the tag is the component type.

A associação de atributo diferencia maiúsculas de minúsculas.Attribute binding is case sensitive. Por exemplo, @bind é válido e @Bind é inválido.For example, @bind is valid, and @Bind is invalid.

A marcação a seguir no index. Razor renderiza uma instância de HeadingComponent:The following markup in Index.razor renders a HeadingComponent instance:

<HeadingComponent />

Componentes/HeadingComponent. Razor:Components/HeadingComponent.razor:

@using System.Globalization
@*
    The 'using' directive makes System.Globalization available to 
    the component. System.Globalization provides a method for 
    converting a string into title case (capitalizes the first 
    letter of every word in a string), which is used to convert a 
    a string into title case for a heading.
*@

@*
    Heading text is rendered by evaluating the _headingText field. 
    The font-style of the heading is rendered by evaluating the 
    _headingFontStyle field.
*@
<h1 style="font-style:@_headingFontStyle">@_headingText</h1>

<form>
    <div>
        @*
            A check box sets the font style and is bound to the 
            _italicsCheck field.
        *@
        <input type="checkbox" id="italicsCheck" 
               @bind="_italicsCheck" />
        <label class="form-check-label" 
            for="italicsCheck">Use italics</label>
    </div>

    @*
        When the form is submitted, the onclick event executes 
        the UpdateHeading method.
    *@
    <button type="button" class="btn btn-primary" @onclick="UpdateHeading">
        Update heading
    </button>
</form>

@code {
    private static TextInfo _tinfo = CultureInfo.CurrentCulture.TextInfo;
    private string _headingText = 
        _tinfo.ToTitleCase("welcome to blazor!");
    private string _headingFontStyle = "normal";
    private bool _italicsCheck = false;

    // When UpdateHeading is executed, _italicsCheck determines 
    // the value of _headingFontStyle to set the font style of the 
    // heading.
    public void UpdateHeading()
    {
        _headingFontStyle = _italicsCheck ? "italic" : "normal";
    }
}

Se um componente contiver um elemento HTML com uma letra maiúscula ou minúscula que não corresponda a um nome de componente, um aviso será emitido indicando que o elemento tem um nome inesperado.If a component contains an HTML element with an uppercase first letter that doesn't match a component name, a warning is emitted indicating that the element has an unexpected name. Adicionar uma instrução @using para o namespace do componente disponibiliza o componente, o que remove o aviso.Adding an @using statement for the component's namespace makes the component available, which removes the warning.

Parâmetros do componenteComponent parameters

Os componentes podem ter parâmetros de componente, que são definidos usando propriedades públicas na classe de componente com o atributo [Parameter].Components can have component parameters, which are defined using public properties on the component class with the [Parameter] attribute. Use atributos para especificar argumentos para um componente na marcação.Use attributes to specify arguments for a component in markup.

Componentes/ChildComponent. Razor:Components/ChildComponent.razor:

<div class="panel panel-default">
    <div class="panel-heading">@Title</div>
    <div class="panel-body">@ChildContent</div>

    <button class="btn btn-primary" @onclick="OnClick">
        Trigger a Parent component method
    </button>
</div>

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

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

    [Parameter]
    public EventCallback<MouseEventArgs> OnClick { get; set; }
}

No exemplo a seguir, o ParentComponent define o valor da propriedade Title do ChildComponent.In the following example, the ParentComponent sets the value of the Title property of the ChildComponent.

Páginas/ParentComponent. Razor:Pages/ParentComponent.razor:

@page "/ParentComponent"

<h1>Parent-child example</h1>

<ChildComponent Title="Panel Title from Parent"
                OnClick="@ShowMessage">
    Content of the child component is supplied
    by the parent component.
</ChildComponent>

<p><b>@messageText</b></p>

@code {
    private string messageText;

    private void ShowMessage(MouseEventArgs e)
    {
        messageText = $"Blaze a new trail with Blazor! ({e.ScreenX}, {e.ScreenY})";
    }
}

Conteúdo filhoChild content

Os componentes podem definir o conteúdo de outro componente.Components can set the content of another component. O componente de atribuição fornece o conteúdo entre as marcas que especificam o componente de recebimento.The assigning component provides the content between the tags that specify the receiving component.

No exemplo a seguir, o ChildComponent tem uma propriedade ChildContent que representa um RenderFragment, que representa um segmento de interface do usuário a ser renderizado.In the following example, the ChildComponent has a ChildContent property that represents a RenderFragment, which represents a segment of UI to render. O valor de ChildContent é posicionado na marcação do componente onde o conteúdo deve ser renderizado.The value of ChildContent is positioned in the component's markup where the content should be rendered. O valor de ChildContent é recebido do componente pai e renderizado dentro do panel-bodydo painel de inicialização.The value of ChildContent is received from the parent component and rendered inside the Bootstrap panel's panel-body.

Componentes/ChildComponent. Razor:Components/ChildComponent.razor:

<div class="panel panel-default">
    <div class="panel-heading">@Title</div>
    <div class="panel-body">@ChildContent</div>

    <button class="btn btn-primary" @onclick="OnClick">
        Trigger a Parent component method
    </button>
</div>

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

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

    [Parameter]
    public EventCallback<MouseEventArgs> OnClick { get; set; }
}

Observação

A propriedade que recebe o conteúdo de RenderFragment deve ser nomeada ChildContent por convenção.The property receiving the RenderFragment content must be named ChildContent by convention.

Os ParentComponent a seguir podem fornecer conteúdo para renderizar o ChildComponent colocando o conteúdo dentro das marcas de <ChildComponent>.The following ParentComponent can provide content for rendering the ChildComponent by placing the content inside the <ChildComponent> tags.

Páginas/ParentComponent. Razor:Pages/ParentComponent.razor:

@page "/ParentComponent"

<h1>Parent-child example</h1>

<ChildComponent Title="Panel Title from Parent"
                OnClick="@ShowMessage">
    Content of the child component is supplied
    by the parent component.
</ChildComponent>

<p><b>@messageText</b></p>

@code {
    private string messageText;

    private void ShowMessage(MouseEventArgs e)
    {
        messageText = $"Blaze a new trail with Blazor! ({e.ScreenX}, {e.ScreenY})";
    }
}

Atributo nivelamento e parâmetros arbitráriosAttribute splatting and arbitrary parameters

Os componentes podem capturar e renderizar atributos adicionais além dos parâmetros declarados do componente.Components can capture and render additional attributes in addition to the component's declared parameters. Atributos adicionais podem ser capturados em um dicionário e, em seguida, splatted em um elemento quando o componente é renderizado usando a diretiva @attributes Razor.Additional attributes can be captured in a dictionary and then splatted onto an element when the component is rendered using the @attributes Razor directive. Esse cenário é útil ao definir um componente que produz um elemento de marcação que dá suporte a uma variedade de personalizações.This scenario is useful when defining a component that produces a markup element that supports a variety of customizations. Por exemplo, pode ser entediante definir atributos separadamente para um <input> que ofereça suporte a muitos parâmetros.For example, it can be tedious to define attributes separately for an <input> that supports many parameters.

No exemplo a seguir, o primeiro elemento <input> (id="useIndividualParams") usa parâmetros de componente individuais, enquanto o segundo elemento <input> (id="useAttributesDict") usa o atributo nivelamento:In the following example, the first <input> element (id="useIndividualParams") uses individual component parameters, while the second <input> element (id="useAttributesDict") uses attribute splatting:

<input id="useIndividualParams"
       maxlength="@Maxlength"
       placeholder="@Placeholder"
       required="@Required"
       size="@Size" />

<input id="useAttributesDict"
       @attributes="InputAttributes" />

@code {
    [Parameter]
    public string Maxlength { get; set; } = "10";

    [Parameter]
    public string Placeholder { get; set; } = "Input placeholder text";

    [Parameter]
    public string Required { get; set; } = "required";

    [Parameter]
    public string Size { get; set; } = "50";

    [Parameter]
    public Dictionary<string, object> InputAttributes { get; set; } =
        new Dictionary<string, object>()
        {
            { "maxlength", "10" },
            { "placeholder", "Input placeholder text" },
            { "required", "required" },
            { "size", "50" }
        };
}

O tipo do parâmetro deve implementar IEnumerable<KeyValuePair<string, object>> com chaves de cadeia de caracteres.The type of the parameter must implement IEnumerable<KeyValuePair<string, object>> with string keys. Usar IReadOnlyDictionary<string, object> também é uma opção nesse cenário.Using IReadOnlyDictionary<string, object> is also an option in this scenario.

Os elementos <input> renderizados usando ambas as abordagens são idênticos:The rendered <input> elements using both approaches is identical:

<input id="useIndividualParams"
       maxlength="10"
       placeholder="Input placeholder text"
       required="required"
       size="50">

<input id="useAttributesDict"
       maxlength="10"
       placeholder="Input placeholder text"
       required="required"
       size="50">

Para aceitar atributos arbitrários, defina um parâmetro de componente usando o atributo [Parameter] com a propriedade CaptureUnmatchedValues definida como true:To accept arbitrary attributes, define a component parameter using the [Parameter] attribute with the CaptureUnmatchedValues property set to true:

@code {
    [Parameter(CaptureUnmatchedValues = true)]
    public Dictionary<string, object> InputAttributes { get; set; }
}

A propriedade CaptureUnmatchedValues em [Parameter] permite que o parâmetro corresponda a todos os atributos que não correspondem a nenhum outro parâmetro.The CaptureUnmatchedValues property on [Parameter] allows the parameter to match all attributes that don't match any other parameter. Um componente só pode definir um único parâmetro com CaptureUnmatchedValues.A component can only define a single parameter with CaptureUnmatchedValues. O tipo de propriedade usado com CaptureUnmatchedValues deve ser atribuível de Dictionary<string, object> com chaves de cadeia de caracteres.The property type used with CaptureUnmatchedValues must be assignable from Dictionary<string, object> with string keys. IEnumerable<KeyValuePair<string, object>> ou IReadOnlyDictionary<string, object> também são opções neste cenário.IEnumerable<KeyValuePair<string, object>> or IReadOnlyDictionary<string, object> are also options in this scenario.

A posição de @attributes em relação à posição dos atributos do elemento é importante.The position of @attributes relative to the position of element attributes is important. Quando @attributes são splatted no elemento, os atributos são processados da direita para a esquerda (último a primeiro).When @attributes are splatted on the element, the attributes are processed from right to left (last to first). Considere o exemplo a seguir de um componente que consome um componente Child:Consider the following example of a component that consumes a Child component:

ParentComponent. Razor:ParentComponent.razor:

<ChildComponent extra="10" />

ChildComponent. Razor:ChildComponent.razor:

<div @attributes="AdditionalAttributes" extra="5" />

[Parameter(CaptureUnmatchedValues = true)]
public IDictionary<string, object> AdditionalAttributes { get; set; }

O atributo extra do componente de Child é definido à direita de @attributes.The Child component's extra attribute is set to the right of @attributes. O <div> renderizado do componente Parent contém extra="5" quando passa pelo atributo adicional porque os atributos são processados da direita para a esquerda (último a primeiro):The Parent component's rendered <div> contains extra="5" when passed through the additional attribute because the attributes are processed right to left (last to first):

<div extra="5" />

No exemplo a seguir, a ordem de extra e @attributes é revertida na <div>do componente Child:In the following example, the order of extra and @attributes is reversed in the Child component's <div>:

ParentComponent. Razor:ParentComponent.razor:

<ChildComponent extra="10" />

ChildComponent. Razor:ChildComponent.razor:

<div extra="5" @attributes="AdditionalAttributes" />

[Parameter(CaptureUnmatchedValues = true)]
public IDictionary<string, object> AdditionalAttributes { get; set; }

O <div> renderizado no componente Parent contém extra="10" quando passado pelo atributo adicional:The rendered <div> in the Parent component contains extra="10" when passed through the additional attribute:

<div extra="10" />

Associação de dadosData binding

A vinculação de dados para os componentes e os elementos DOM é realizada com o atributo @bind .Data binding to both components and DOM elements is accomplished with the @bind attribute. O exemplo a seguir associa uma propriedade CurrentValue ao valor da caixa de texto:The following example binds a CurrentValue property to the text box's value:

<input @bind="CurrentValue" />

@code {
    private string CurrentValue { get; set; }
}

Quando a caixa de texto perde o foco, o valor da propriedade é atualizado.When the text box loses focus, the property's value is updated.

A caixa de texto é atualizada na interface do usuário somente quando o componente é renderizado, não em resposta à alteração do valor da propriedade.The text box is updated in the UI only when the component is rendered, not in response to changing the property's value. Como os componentes são renderizados após a execução do código do manipulador de eventos, as atualizações de propriedade geralmente são refletidas na interface do usuário imediatamente após um manipulador de eventos ser disparado.Since components render themselves after event handler code executes, property updates are usually reflected in the UI immediately after an event handler is triggered.

O uso de @bind com a propriedade CurrentValue (<input @bind="CurrentValue" />) é essencialmente equivalente ao seguinte:Using @bind with the CurrentValue property (<input @bind="CurrentValue" />) is essentially equivalent to the following:

<input value="@CurrentValue"
    @onchange="@((ChangeEventArgs __e) => CurrentValue = 
        __e.Value.ToString())" />
        
@code {
    private string CurrentValue { get; set; }
}

Quando o componente é renderizado, a value do elemento input é proveniente da propriedade CurrentValue.When the component is rendered, the value of the input element comes from the CurrentValue property. Quando o usuário digita na caixa de texto e altera o foco do elemento, o evento onchange é acionado e a propriedade CurrentValue é definida como o valor alterado.When the user types in the text box and changes element focus, the onchange event is fired and the CurrentValue property is set to the changed value. Na realidade, a geração de código é mais complexa porque @bind trata casos em que conversões de tipo são executadas.In reality, the code generation is more complex because @bind handles cases where type conversions are performed. Em princípio, @bind associa o valor atual de uma expressão a um atributo value e manipula as alterações usando o manipulador registrado.In principle, @bind associates the current value of an expression with a value attribute and handles changes using the registered handler.

Além de manipular onchange eventos com a sintaxe @bind, uma propriedade ou um campo pode ser associado usando outros eventos, especificando um atributo @bind-value com um parâmetro event (@bind-value:event).In addition to handling onchange events with @bind syntax, a property or field can be bound using other events by specifying an @bind-value attribute with an event parameter (@bind-value:event). O exemplo a seguir associa a propriedade CurrentValue para o evento oninput:The following example binds the CurrentValue property for the oninput event:

<input @bind-value="CurrentValue" @bind-value:event="oninput" />

@code {
    private string CurrentValue { get; set; }
}

Ao contrário de onchange, que é disparado quando o elemento perde o foco, oninput é acionado quando o valor da caixa de texto é alterado.Unlike onchange, which fires when the element loses focus, oninput fires when the value of the text box changes.

Valores não analisáveisUnparsable values

Quando um usuário fornece um valor não analisável para um elemento de ligação de valores, o valor não analisável é revertido automaticamente para seu valor anterior quando o evento de ligação é disparado.When a user provides an unparsable value to a databound element, the unparsable value is automatically reverted to its previous value when the bind event is triggered.

Considere o seguinte cenário:Consider the following scenario:

  • Um elemento <input> está associado a um tipo de int com um valor inicial de 123:An <input> element is bound to an int type with an initial value of 123:

    <input @bind="MyProperty" />
    
    @code {
        [Parameter]
        public int MyProperty { get; set; } = 123;
    }
    
  • O usuário atualiza o valor do elemento para 123.45 na página e altera o foco do elemento.The user updates the value of the element to 123.45 in the page and changes the element focus.

No cenário anterior, o valor do elemento é revertido para 123.In the preceding scenario, the element's value is reverted to 123. Quando o valor 123.45 é rejeitado em favor do valor original de 123, o usuário entende que seu valor não foi aceito.When the value 123.45 is rejected in favor of the original value of 123, the user understands that their value wasn't accepted.

Por padrão, a associação aplica-se ao evento de onchange do elemento (@bind="{PROPERTY OR FIELD}").By default, binding applies to the element's onchange event (@bind="{PROPERTY OR FIELD}"). Use @bind-value="{PROPERTY OR FIELD}" @bind-value:event={EVENT} para definir um evento diferente.Use @bind-value="{PROPERTY OR FIELD}" @bind-value:event={EVENT} to set a different event. Para o evento de oninput (@bind-value:event="oninput"), a reversão ocorre após qualquer pressionamento de tecla que introduz um valor não analisável.For the oninput event (@bind-value:event="oninput"), the reversion occurs after any keystroke that introduces an unparsable value. Ao direcionar o evento de oninput com um tipo de associação de int, um usuário é impedido de digitar um caractere ..When targeting the oninput event with an int-bound type, a user is prevented from typing a . character. Um caractere . é removido imediatamente e, portanto, o usuário recebe comentários imediatos de que apenas números inteiros são permitidos.A . character is immediately removed, so the user receives immediate feedback that only whole numbers are permitted. Há cenários em que a reversão do valor no evento oninput não é ideal, por exemplo, quando o usuário deve ter permissão para limpar um valor de <input> não analisável.There are scenarios where reverting the value on the oninput event isn't ideal, such as when the user should be allowed to clear an unparsable <input> value. As alternativas incluem:Alternatives include:

  • Não use o evento oninput.Don't use the oninput event. Use o evento de onchange padrão (@bind="{PROPERTY OR FIELD}"), em que um valor inválido não é revertido até que o elemento perca o foco.Use the default onchange event (@bind="{PROPERTY OR FIELD}"), where an invalid value isn't reverted until the element loses focus.
  • Associar a um tipo anulável, como int? ou string, e fornecer uma lógica personalizada para manipular entradas inválidas.Bind to a nullable type, such as int? or string, and provide custom logic to handle invalid entries.
  • Use um componente de validação de formulário, como InputNumber ou InputDate.Use a form validation component, such as InputNumber or InputDate. Os componentes de validação de formulário têm suporte interno para gerenciar entradas inválidas.Form validation components have built-in support to manage invalid inputs. Componentes de validação de formulário:Form validation components:
    • Permitir que o usuário forneça erros de entrada e de validação inválidos no EditContextassociado.Permit the user to provide invalid input and receive validation errors on the associated EditContext.
    • Exibir erros de validação na interface de usuário sem interferir no usuário inserindo dados adicionais do WebForms.Display validation errors in the UI without interfering with the user entering additional webform data.

GlobalizaçãoGlobalization

@bind valores são formatados para exibição e analisados usando as regras da cultura atual.@bind values are formatted for display and parsed using the current culture's rules.

A cultura atual pode ser acessada a partir da propriedade System.Globalization.CultureInfo.CurrentCulture.The current culture can be accessed from the System.Globalization.CultureInfo.CurrentCulture property.

CultureInfo. InvariantCulture é usado para os seguintes tipos de campo (<input type="{TYPE}" />):CultureInfo.InvariantCulture is used for the following field types (<input type="{TYPE}" />):

  • date
  • number

Os tipos de campo anteriores:The preceding field types:

  • São exibidos usando suas regras de formatação baseadas em navegador apropriadas.Are displayed using their appropriate browser-based formatting rules.
  • Não pode conter texto de forma livre.Can't contain free-form text.
  • Fornecer características de interação do usuário com base na implementação do navegador.Provide user interaction characteristics based on the browser's implementation.

Os seguintes tipos de campo têm requisitos de formatação específicos e atualmente não têm suporte do Blazor porque eles não têm suporte em todos os principais navegadores:The following field types have specific formatting requirements and aren't currently supported by Blazor because they aren't supported by all major browsers:

  • datetime-local
  • month
  • week

@bind dá suporte ao parâmetro @bind:culture para fornecer um System.Globalization.CultureInfo para análise e formatação de um valor.@bind supports the @bind:culture parameter to provide a System.Globalization.CultureInfo for parsing and formatting a value. Não é recomendável especificar uma cultura ao usar os tipos de campo date e number.Specifying a culture isn't recommended when using the date and number field types. date e number têm suporte interno a Blazor que fornece a cultura necessária.date and number have built-in Blazor support that provides the required culture.

Para obter informações sobre como definir a cultura do usuário, consulte a seção localização .For information on how to set the user's culture, see the Localization section.

Formatar cadeias de caracteresFormat strings

A vinculação de dados funciona com DateTime cadeias de caracteres de formato usando @bind:format.Data binding works with DateTime format strings using @bind:format. Outras expressões de formato, como formatos de moeda ou número, não estão disponíveis no momento.Other format expressions, such as currency or number formats, aren't available at this time.

<input @bind="StartDate" @bind:format="yyyy-MM-dd" />

@code {
    [Parameter]
    public DateTime StartDate { get; set; } = new DateTime(2020, 1, 1);
}

No código anterior, o tipo de campo (type) do elemento <input> tem como padrão text.In the preceding code, the <input> element's field type (type) defaults to text. @bind:format tem suporte para ligar os seguintes tipos .NET:@bind:format is supported for binding the following .NET types:

O atributo @bind:format especifica o formato de data a ser aplicado ao value do elemento <input>.The @bind:format attribute specifies the date format to apply to the value of the <input> element. O formato também é usado para analisar o valor quando ocorre um evento onchange.The format is also used to parse the value when an onchange event occurs.

Não é recomendável especificar um formato para o tipo de campo date porque Blazor tem suporte interno para formatar datas.Specifying a format for the date field type isn't recommended because Blazor has built-in support to format dates. Apesar da recomendação, use apenas o formato de data yyyy-MM-dd para que a associação funcione corretamente se um formato for fornecido com o tipo de campo date:In spite of the recommendation, only use the yyyy-MM-dd date format for binding to work correctly if a format is supplied with the date field type:

<input type="date" @bind="StartDate" @bind:format="yyyy-MM-dd">

Parâmetros do componenteComponent parameters

A associação reconhece os parâmetros do componente, em que @bind-{property} pode associar um valor de propriedade entre componentes.Binding recognizes component parameters, where @bind-{property} can bind a property value across components.

O componente filho a seguir (ChildComponent) tem um parâmetro de componente Year e YearChanged retorno de chamada:The following child component (ChildComponent) has a Year component parameter and YearChanged callback:

<h2>Child Component</h2>

<p>Year: @Year</p>

@code {
    [Parameter]
    public int Year { get; set; }

    [Parameter]
    public EventCallback<int> YearChanged { get; set; }
}

EventCallback<T> é explicado na seção EventCallback .EventCallback<T> is explained in the EventCallback section.

O componente pai a seguir usa ChildComponent e associa o parâmetro ParentYear do pai ao parâmetro Year no componente filho:The following parent component uses ChildComponent and binds the ParentYear parameter from the parent to the Year parameter on the child component:

@page "/ParentComponent"

<h1>Parent Component</h1>

<p>ParentYear: @ParentYear</p>

<ChildComponent @bind-Year="ParentYear" />

<button class="btn btn-primary" @onclick="ChangeTheYear">
    Change Year to 1986
</button>

@code {
    [Parameter]
    public int ParentYear { get; set; } = 1978;

    private void ChangeTheYear()
    {
        ParentYear = 1986;
    }
}

Carregar o ParentComponent produz a seguinte marcação:Loading the ParentComponent produces the following markup:

<h1>Parent Component</h1>

<p>ParentYear: 1978</p>

<h2>Child Component</h2>

<p>Year: 1978</p>

Se o valor da propriedade ParentYear for alterado selecionando o botão na ParentComponent, a propriedade Year do ChildComponent será atualizada.If the value of the ParentYear property is changed by selecting the button in the ParentComponent, the Year property of the ChildComponent is updated. O novo valor de Year é renderizado na interface do usuário quando a ParentComponent é reprocessada:The new value of Year is rendered in the UI when the ParentComponent is rerendered:

<h1>Parent Component</h1>

<p>ParentYear: 1986</p>

<h2>Child Component</h2>

<p>Year: 1986</p>

O parâmetro Year é acoplável porque tem um evento complementar YearChanged que corresponde ao tipo do parâmetro Year.The Year parameter is bindable because it has a companion YearChanged event that matches the type of the Year parameter.

Por convenção, <ChildComponent @bind-Year="ParentYear" /> é essencialmente equivalente a escrever:By convention, <ChildComponent @bind-Year="ParentYear" /> is essentially equivalent to writing:

<ChildComponent @bind-Year="ParentYear" @bind-Year:event="YearChanged" />

Em geral, uma propriedade pode ser associada a um manipulador de eventos correspondente usando @bind-property:event atributo.In general, a property can be bound to a corresponding event handler using @bind-property:event attribute. Por exemplo, a propriedade MyProp pode ser associada a MyEventHandler usando os dois atributos a seguir:For example, the property MyProp can be bound to MyEventHandler using the following two attributes:

<MyComponent @bind-MyProp="MyValue" @bind-MyProp:event="MyEventHandler" />

Manipulação de eventosEvent handling

Os componentes do Razor fornecem recursos de manipulação de eventos.Razor components provide event handling features. Para um atributo de elemento HTML chamado on{EVENT} (por exemplo, onclick e onsubmit) com um valor de tipo delegado, os componentes do Razor tratam o valor do atributo como um manipulador de eventos.For an HTML element attribute named on{EVENT} (for example, onclick and onsubmit) with a delegate-typed value, Razor components treats the attribute's value as an event handler. O nome do atributo é sempre formatado @on{EVENT}.The attribute's name is always formatted @on{EVENT}.

O código a seguir chama o método UpdateHeading quando o botão é selecionado na interface do usuário:The following code calls the UpdateHeading method when the button is selected in the UI:

<button class="btn btn-primary" @onclick="UpdateHeading">
    Update heading
</button>

@code {
    private void UpdateHeading(MouseEventArgs e)
    {
        ...
    }
}

O código a seguir chama o método CheckChanged quando a caixa de seleção é alterada na interface do usuário:The following code calls the CheckChanged method when the check box is changed in the UI:

<input type="checkbox" class="form-check-input" @onchange="CheckChanged" />

@code {
    private void CheckChanged()
    {
        ...
    }
}

Os manipuladores de eventos também podem ser assíncronos e retornar um Task.Event handlers can also be asynchronous and return a Task. Não é necessário chamar StateHasChangedmanualmente.There's no need to manually call StateHasChanged. As exceções são registradas quando ocorrem.Exceptions are logged when they occur.

No exemplo a seguir, UpdateHeading é chamado de forma assíncrona quando o botão é selecionado:In the following example, UpdateHeading is called asynchronously when the button is selected:

<button class="btn btn-primary" @onclick="UpdateHeading">
    Update heading
</button>

@code {
    private async Task UpdateHeading(MouseEventArgs e)
    {
        ...
    }
}

Tipos de argumento de eventoEvent argument types

Para alguns eventos, são permitidos tipos de argumento de evento.For some events, event argument types are permitted. Se o acesso a um desses tipos de evento não for necessário, ele não será necessário na chamada do método.If access to one of these event types isn't necessary, it isn't required in the method call.

Os EventArgs com suporte são mostrados na tabela a seguir.Supported EventArgs are shown in the following table.

EventEvent ClasseClass Eventos e observações do DOMDOM events and notes
Área de transferênciaClipboard ClipboardEventArgs oncut, oncopy, onpasteoncut, oncopy, onpaste
ArrastarDrag DragEventArgs ondrag, ondragstart, ondragenter, ondragleave, ondragover, ondrop, ondragendondrag, ondragstart, ondragenter, ondragleave, ondragover, ondrop, ondragend

DataTransfer e DataTransferItem manter os dados do item arrastados.DataTransfer and DataTransferItem hold dragged item data.
Erro doError ErrorEventArgs onerror
EventEvent EventArgs GeralGeneral
onactivate, onbeforeactivate, onbeforedeactivate, ondeactivate, onended, onfullscreenchange, onfullscreenerror, onloadeddata, onloadedmetadata, onpointerlockchange, onpointerlockerror, onreadystatechange, onscrollonactivate, onbeforeactivate, onbeforedeactivate, ondeactivate, onended, onfullscreenchange, onfullscreenerror, onloadeddata, onloadedmetadata, onpointerlockchange, onpointerlockerror, onreadystatechange, onscroll

Área de transferênciaClipboard
onbeforecut, onbeforecopy, onbeforepasteonbeforecut, onbeforecopy, onbeforepaste

EntradaInput
oninvalid, onreset, onselect, onselectionchange, onselectstart, onsubmitoninvalid, onreset, onselect, onselectionchange, onselectstart, onsubmit

MídiaMedia
oncanplay, oncanplaythrough, oncuechange, ondurationchange, onemptied, onpause, onplay, onplaying, onratechange, onseeked, onseeking, onstalled, onstop, onsuspend, ontimeupdate, onvolumechange, onwaitingoncanplay, oncanplaythrough, oncuechange, ondurationchange, onemptied, onpause, onplay, onplaying, onratechange, onseeked, onseeking, onstalled, onstop, onsuspend, ontimeupdate, onvolumechange, onwaiting
FocoFocus FocusEventArgs onfocus, onblur, onfocusin, onfocusoutonfocus, onblur, onfocusin, onfocusout

Não inclui suporte para relatedTarget.Doesn't include support for relatedTarget.
EntradaInput ChangeEventArgs onchange, oninputonchange, oninput
TecladoKeyboard KeyboardEventArgs onkeydown, onkeypress, onkeyuponkeydown, onkeypress, onkeyup
MouseMouse MouseEventArgs onclick, oncontextmenu, ondblclick, onmousedown, onmouseup, onmouseover, onmousemove, onmouseoutonclick, oncontextmenu, ondblclick, onmousedown, onmouseup, onmouseover, onmousemove, onmouseout
Ponteiro do mouseMouse pointer PointerEventArgs onpointerdown, onpointerup, onpointercancel, onpointermove, onpointerover, onpointerout, onpointerenter, onpointerleave, ongotpointercapture, onlostpointercaptureonpointerdown, onpointerup, onpointercancel, onpointermove, onpointerover, onpointerout, onpointerenter, onpointerleave, ongotpointercapture, onlostpointercapture
Botão de rolagem do mouseMouse wheel WheelEventArgs onwheel, onmousewheelonwheel, onmousewheel
ProgressoProgress ProgressEventArgs onabort, onload, onloadend, onloadstart, onprogress, ontimeoutonabort, onload, onloadend, onloadstart, onprogress, ontimeout
ToqueTouch TouchEventArgs ontouchstart, ontouchend, ontouchmove, ontouchenter, ontouchleave, ontouchcancelontouchstart, ontouchend, ontouchmove, ontouchenter, ontouchleave, ontouchcancel

TouchPoint representa um único ponto de contato em um dispositivo sensível ao toque.TouchPoint represents a single contact point on a touch-sensitive device.

Para obter informações sobre as propriedades e o comportamento de manipulação de eventos dos eventos na tabela anterior, consulte classes EventArgs na fonte de referência (ramificação ASPNET/AspNetCore Release/3.0).For information on the properties and event handling behavior of the events in the preceding table, see EventArgs classes in the reference source (aspnet/AspNetCore release/3.0 branch).

Expressões lambdaLambda expressions

As expressões lambda também podem ser usadas:Lambda expressions can also be used:

<button @onclick="@(e => Console.WriteLine("Hello, world!"))">Say hello</button>

Geralmente, é conveniente fechar valores adicionais, como ao iterar em um conjunto de elementos.It's often convenient to close over additional values, such as when iterating over a set of elements. O exemplo a seguir cria três botões, cada um dos quais chamadas UpdateHeading passando um argumento de evento (MouseEventArgs) e seu número de botão (buttonNumber) quando selecionado na interface do usuário:The following example creates three buttons, each of which calls UpdateHeading passing an event argument (MouseEventArgs) and its button number (buttonNumber) when selected in the UI:

<h2>@message</h2>

@for (var i = 1; i < 4; i++)
{
    var buttonNumber = i;

    <button class="btn btn-primary"
            @onclick="@(e => UpdateHeading(e, buttonNumber))">
        Button #@i
    </button>
}

@code {
    private string message = "Select a button to learn its position.";

    private void UpdateHeading(MouseEventArgs e, int buttonNumber)
    {
        message = $"You selected Button #{buttonNumber} at " +
            $"mouse position: {e.ClientX} X {e.ClientY}.";
    }
}

Observação

Não use a variável de loop (i) em um loop de for diretamente em uma expressão lambda.Do not use the loop variable (i) in a for loop directly in a lambda expression. Caso contrário, a mesma variável é usada por todas as expressões lambda, fazendo com que ivalor seja o mesmo em todos os lambdas.Otherwise the same variable is used by all lambda expressions causing i's value to be the same in all lambdas. Sempre Capture seu valor em uma variável local (buttonNumber no exemplo anterior) e, em seguida, use-o.Always capture its value in a local variable (buttonNumber in the preceding example) and then use it.

EventCallbackEventCallback

Um cenário comum com componentes aninhados é o desejo de executar o método de um componente pai quando ocorre um evento de componente filho—por exemplo, quando um evento de onclick ocorre no filho.A common scenario with nested components is the desire to run a parent component's method when a child component event occurs—for example, when an onclick event occurs in the child. Para expor eventos entre componentes, use um EventCallback.To expose events across components, use an EventCallback. Um componente pai pode atribuir um método de retorno de chamada para o EventCallbackde um componente filho.A parent component can assign a callback method to a child component's EventCallback.

O ChildComponent no aplicativo de exemplo demonstra como o manipulador de onclick de um botão é configurado para receber um delegado de EventCallback da ParentComponentde exemplo.The ChildComponent in the sample app demonstrates how a button's onclick handler is set up to receive an EventCallback delegate from the sample's ParentComponent. O EventCallback é digitado com MouseEventArgs, que é apropriado para um evento de onclick de um dispositivo periférico:The EventCallback is typed with MouseEventArgs, which is appropriate for an onclick event from a peripheral device:

<div class="panel panel-default">
    <div class="panel-heading">@Title</div>
    <div class="panel-body">@ChildContent</div>

    <button class="btn btn-primary" @onclick="OnClick">
        Trigger a Parent component method
    </button>
</div>

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

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

    [Parameter]
    public EventCallback<MouseEventArgs> OnClick { get; set; }
}

O ParentComponent define o EventCallback<T> do filho como seu método ShowMessage:The ParentComponent sets the child's EventCallback<T> to its ShowMessage method:

@page "/ParentComponent"

<h1>Parent-child example</h1>

<ChildComponent Title="Panel Title from Parent"
                OnClick="@ShowMessage">
    Content of the child component is supplied
    by the parent component.
</ChildComponent>

<p><b>@messageText</b></p>

@code {
    private string messageText;

    private void ShowMessage(MouseEventArgs e)
    {
        messageText = $"Blaze a new trail with Blazor! ({e.ScreenX}, {e.ScreenY})";
    }
}

Quando o botão estiver selecionado na ChildComponent:When the button is selected in the ChildComponent:

  • O método ShowMessage do ParentComponenté chamado.The ParentComponent's ShowMessage method is called. messageText é atualizado e exibido no ParentComponent.messageText is updated and displayed in the ParentComponent.
  • Uma chamada para StateHasChanged não é necessária no método do retorno de chamada (ShowMessage).A call to StateHasChanged isn't required in the callback's method (ShowMessage). StateHasChanged é chamado automaticamente para renderizar novamente o ParentComponent, assim como os eventos filho disparam o reprocessamento de componentes em manipuladores de eventos que são executados dentro do filho.StateHasChanged is called automatically to rerender the ParentComponent, just as child events trigger component rerendering in event handlers that execute within the child.

EventCallback e EventCallback<T> permitir delegados assíncronos.EventCallback and EventCallback<T> permit asynchronous delegates. EventCallback<T> é fortemente tipado e requer um tipo de argumento específico.EventCallback<T> is strongly typed and requires a specific argument type. EventCallback é digitado de forma fraca e permite qualquer tipo de argumento.EventCallback is weakly typed and allows any argument type.

<p><b>@messageText</b></p>

@{ var message = "Default Text"; }

<ChildComponent 
    OnClick="@(async () => { await Task.Yield(); messageText = "Blaze It!"; })" />

@code {
    private string messageText;
}

Invoque um EventCallback ou EventCallback<T> com InvokeAsync e aguardar a Task:Invoke an EventCallback or EventCallback<T> with InvokeAsync and await the Task:

await callback.InvokeAsync(arg);

Use EventCallback e EventCallback<T> para manipulação de eventos e parâmetros de componente de associação.Use EventCallback and EventCallback<T> for event handling and binding component parameters.

Prefira a EventCallback<T> com rigidez de tipos sobre EventCallback.Prefer the strongly typed EventCallback<T> over EventCallback. EventCallback<T> fornece melhores comentários de erro para os usuários do componente.EventCallback<T> provides better error feedback to users of the component. Semelhante a outros manipuladores de eventos de interface do usuário, especificar o parâmetro de evento é opcional.Similar to other UI event handlers, specifying the event parameter is optional. Use EventCallback quando não houver valor passado para o retorno de chamada.Use EventCallback when there's no value passed to the callback.

Impedir ações padrãoPrevent default actions

Use o atributo de diretiva @on{EVENT}:preventDefault para evitar a ação padrão para um evento.Use the @on{EVENT}:preventDefault directive attribute to prevent the default action for an event.

Quando uma chave é selecionada em um dispositivo de entrada e o foco do elemento está em uma caixa de texto, um navegador normalmente exibe o caractere da chave na caixa de texto.When a key is selected on an input device and the element focus is on a text box, a browser normally displays the key's character in the text box. No exemplo a seguir, o comportamento padrão é impedido pela especificação do atributo de diretiva @onkeypress:preventDefault.In the following example, the default behavior is prevented by specifying the @onkeypress:preventDefault directive attribute. O contador é incrementado e a chave de + não é capturada no valor do elemento de <input>:The counter increments, and the + key isn't captured into the <input> element's value:

<input value="@_count" @onkeypress="KeyHandler" @onkeypress:preventDefault />

@code {
    private int _count = 0;

    private void KeyHandler(KeyboardEventArgs e)
    {
        if (e.Key == "+")
        {
            _count++;
        }
    }
}

Especificar o atributo @on{EVENT}:preventDefault sem um valor é equivalente a @on{EVENT}:preventDefault="true".Specifying the @on{EVENT}:preventDefault attribute without a value is equivalent to @on{EVENT}:preventDefault="true".

O valor do atributo também pode ser uma expressão.The value of the attribute can also be an expression. No exemplo a seguir, _shouldPreventDefault é um campo de bool definido como true ou false:In the following example, _shouldPreventDefault is a bool field set to either true or false:

<input @onkeypress:preventDefault="_shouldPreventDefault" />

Um manipulador de eventos não é necessário para impedir a ação padrão.An event handler isn't required to prevent the default action. O manipulador de eventos e a prevenção de cenários de ação padrão podem ser usados de forma independente.The event handler and prevent default action scenarios can be used independently.

Parar a propagação do eventoStop event propagation

Use o atributo de diretiva @on{EVENT}:stopPropagation para parar a propagação do evento.Use the @on{EVENT}:stopPropagation directive attribute to stop event propagation.

No exemplo a seguir, marcar a caixa de seleção impede que eventos de clique do segundo filho <div> sejam propagados para o <div>pai:In the following example, selecting the check box prevents click events from the second child <div> from propagating to the parent <div>:

<label>
    <input @bind="_stopPropagation" type="checkbox" />
    Stop Propagation
</label>

<div @onclick="OnSelectParentDiv">
    <h3>Parent div</h3>

    <div @onclick="OnSelectChildDiv">
        Child div that doesn't stop propagation when selected.
    </div>

    <div @onclick="OnSelectChildDiv" @onclick:stopPropagation="_stopPropagation">
        Child div that stops propagation when selected.
    </div>
</div>

@code {
    private bool _stopPropagation = false;

    private void OnSelectParentDiv() => 
        Console.WriteLine($"The parent div was selected. {DateTime.Now}");
    private void OnSelectChildDiv() => 
        Console.WriteLine($"A child div was selected. {DateTime.Now}");
}

Associação encadeadaChained bind

Um cenário comum é encadear um parâmetro de associação de dados a um elemento de página na saída do componente.A common scenario is chaining a data-bound parameter to a page element in the component's output. Esse cenário é chamado de Associação encadeada porque vários níveis de associação ocorrem simultaneamente.This scenario is called a chained bind because multiple levels of binding occur simultaneously.

Uma associação encadeada não pode ser implementada com @bind sintaxe no elemento da página.A chained bind can't be implemented with @bind syntax in the page's element. O manipulador de eventos e o valor devem ser especificados separadamente.The event handler and value must be specified separately. Um componente pai, no entanto, pode usar @bind sintaxe com o parâmetro do componente.A parent component, however, can use @bind syntax with the component's parameter.

O componente PasswordField a seguir (passwordField. Razor):The following PasswordField component (PasswordField.razor):

  • Define um valor de elemento de <input> para uma propriedade Password.Sets an <input> element's value to a Password property.
  • Expõe as alterações da propriedade Password para um componente pai com um EventCallback.Exposes changes of the Password property to a parent component with an EventCallback.
Password: 

<input @oninput="OnPasswordChanged" 
       required 
       type="@(showPassword ? "text" : "password")" 
       value="@Password" />

<button class="btn btn-primary" @onclick="ToggleShowPassword">
    Show password
</button>

@code {
    private bool showPassword;

    [Parameter]
    public string Password { get; set; }

    [Parameter]
    public EventCallback<string> PasswordChanged { get; set; }

    private Task OnPasswordChanged(ChangeEventArgs e)
    {
        Password = e.Value.ToString();

        return PasswordChanged.InvokeAsync(Password);
    }

    private void ToggleShowPassword()
    {
        showPassword = !showPassword;
    }
}

O componente PasswordField é usado em outro componente:The PasswordField component is used in another component:

<PasswordField @bind-Password="password" />

@code {
    private string password;
}

Para executar verificações ou interceptar erros na senha no exemplo anterior:To perform checks or trap errors on the password in the preceding example:

  • Crie um campo de backup para Password (password no código de exemplo a seguir).Create a backing field for Password (password in the following example code).
  • Execute os erros de verificação ou interceptação no setter de Password.Perform the checks or trap errors in the Password setter.

O exemplo a seguir fornecerá comentários imediatos para o usuário se um espaço for usado no valor da senha:The following example provides immediate feedback to the user if a space is used in the password's value:

Password: 

<input @oninput="OnPasswordChanged" 
       required 
       type="@(showPassword ? "text" : "password")" 
       value="@Password" />

<button class="btn btn-primary" @onclick="ToggleShowPassword">
    Show password
</button>

<span class="text-danger">@validationMessage</span>

@code {
    private bool showPassword;
    private string password;
    private string validationMessage;

    [Parameter]
    public string Password
    {
        get { return password ?? string.Empty; }
        set
        {
            if (password != value)
            {
                if (value.Contains(' '))
                {
                    validationMessage = "Spaces not allowed!";
                }
                else
                {
                    password = value;
                    validationMessage = string.Empty;
                }
            }
        }
    }

    [Parameter]
    public EventCallback<string> PasswordChanged { get; set; }

    private Task OnPasswordChanged(ChangeEventArgs e)
    {
        Password = e.Value.ToString();

        return PasswordChanged.InvokeAsync(Password);
    }

    private void ToggleShowPassword()
    {
        showPassword = !showPassword;
    }
}

Capturar referências a componentesCapture references to components

As referências de componente fornecem uma maneira de fazer referência a uma instância de componente para que você possa emitir comandos para essa instância, como Show ou Reset.Component references provide a way to reference a component instance so that you can issue commands to that instance, such as Show or Reset. Para capturar uma referência de componente:To capture a component reference:

  • Adicione um atributo @ref ao componente filho.Add an @ref attribute to the child component.
  • Defina um campo com o mesmo tipo do componente filho.Define a field with the same type as the child component.
<MyLoginDialog @ref="loginDialog" ... />

@code {
    private MyLoginDialog loginDialog;

    private void OnSomething()
    {
        loginDialog.Show();
    }
}

Quando o componente é renderizado, o campo loginDialog é populado com a instância de componente filho MyLoginDialog.When the component is rendered, the loginDialog field is populated with the MyLoginDialog child component instance. Em seguida, você pode invocar os métodos .NET na instância do componente.You can then invoke .NET methods on the component instance.

Importante

A variável loginDialog é populada apenas depois que o componente é renderizado e sua saída inclui o elemento MyLoginDialog.The loginDialog variable is only populated after the component is rendered and its output includes the MyLoginDialog element. Até esse ponto, não há nada a fazer referência.Until that point, there's nothing to reference. Para manipular referências de componentes após a conclusão da renderização do componente, use os métodos OnAfterRenderAsync ou OnAfterRender.To manipulate components references after the component has finished rendering, use the OnAfterRenderAsync or OnAfterRender methods.

Embora a captura de referências de componente use uma sintaxe semelhante à captura de referências de elemento, ela não é um recurso de interoperabilidade do JavaScript .While capturing component references use a similar syntax to capturing element references, it isn't a JavaScript interop feature. As referências de componente não são passadas para o código JavaScript—elas são usadas apenas no código .NET.Component references aren't passed to JavaScript code—they're only used in .NET code.

Observação

Não use referências de componente para converter o estado dos componentes filho.Do not use component references to mutate the state of child components. Em vez disso, use parâmetros declarativos normais para passar dados para componentes filho.Instead, use normal declarative parameters to pass data to child components. O uso de parâmetros declarativos normais resulta em componentes filho que são reprocessados nos horários corretos automaticamente.Use of normal declarative parameters result in child components that rerender at the correct times automatically.

Invocar métodos de componente externamente para atualizar o estadoInvoke component methods externally to update state

Blazor usa uma SynchronizationContext para impor um único thread lógico de execução. uses a SynchronizationContext to enforce a single logical thread of execution. Os métodos de ciclo de vida de um componente e quaisquer retornos de chamada de evento gerados por Blazor são executados nesse SynchronizationContext.A component's lifecycle methods and any event callbacks that are raised by Blazor are executed on this SynchronizationContext. No caso de um componente precisar ser atualizado com base em um evento externo, como um temporizador ou outras notificações, use o método InvokeAsync, que será expedido para o SynchronizationContextde Blazor.In the event a component must be updated based on an external event, such as a timer or other notifications, use the InvokeAsync method, which will dispatch to Blazor's SynchronizationContext.

Por exemplo, considere um serviço de notificação que pode notificar qualquer componente de escuta do estado atualizado:For example, consider a notifier service that can notify any listening component of the updated state:

public class NotifierService
{
    // Can be called from anywhere
    public async Task Update(string key, int value)
    {
        if (Notify != null)
        {
            await Notify.Invoke(key, value);
        }
    }

    public event Func<string, int, Task> Notify;
}

Uso do NotifierService para atualizar um componente:Usage of the NotifierService to update a component:

@page "/"
@inject NotifierService Notifier
@implements IDisposable

<p>Last update: @lastNotification.key = @lastNotification.value</p>

@code {
    private (string key, int value) lastNotification;

    protected override void OnInitialized()
    {
        Notifier.Notify += OnNotify;
    }

    public async Task OnNotify(string key, int value)
    {
        await InvokeAsync(() =>
        {
            lastNotification = (key, value);
            StateHasChanged();
        });
    }

    public void Dispose()
    {
        Notifier.Notify -= OnNotify;
    }
}

No exemplo anterior, NotifierService invoca o método OnNotify do componente fora da SynchronizationContextdo Blazor.In the preceding example, NotifierService invokes the component's OnNotify method outside of Blazor's SynchronizationContext. InvokeAsync é usado para alternar para o contexto correto e enfileirar uma renderização.InvokeAsync is used to switch to the correct context and queue a render.

Use @chave para controlar a preservação de elementos e componentesUse @key to control the preservation of elements and components

Ao renderizar uma lista de elementos ou componentes e os elementos ou componentes subsequentemente mudam, o algoritmo de diferenciação do Blazordeve decidir qual dos elementos ou componentes anteriores podem ser mantidos e como os objetos de modelo devem ser mapeados para eles.When rendering a list of elements or components and the elements or components subsequently change, Blazor's diffing algorithm must decide which of the previous elements or components can be retained and how model objects should map to them. Normalmente, esse processo é automático e pode ser ignorado, mas há casos em que você talvez queira controlar o processo.Normally, this process is automatic and can be ignored, but there are cases where you may want to control the process.

Considere o exemplo a seguir:Consider the following example:

@foreach (var person in People)
{
    <DetailsEditor Details="person.Details" />
}

@code {
    [Parameter]
    public IEnumerable<Person> People { get; set; }
}

O conteúdo da coleção de People pode ser alterado com entradas inseridas, excluídas ou reordenadas.The contents of the People collection may change with inserted, deleted, or re-ordered entries. Quando o componente é rerenderizado, o componente <DetailsEditor> pode ser alterado para receber diferentes valores de parâmetro Details.When the component rerenders, the <DetailsEditor> component may change to receive different Details parameter values. Isso pode causar um reprocessamento mais complexo do que o esperado.This may cause more complex rerendering than expected. Em alguns casos, a rerenderização pode levar a diferenças de comportamento visíveis, como o foco de elemento perdido.In some cases, rerendering can lead to visible behavior differences, such as lost element focus.

O processo de mapeamento pode ser controlado com o atributo de diretiva @key.The mapping process can be controlled with the @key directive attribute. @key faz com que o algoritmo diff garanta a preservação de elementos ou componentes com base no valor da chave:@key causes the diffing algorithm to guarantee preservation of elements or components based on the key's value:

@foreach (var person in People)
{
    <DetailsEditor @key="person" Details="person.Details" />
}

@code {
    [Parameter]
    public IEnumerable<Person> People { get; set; }
}

Quando a coleção de People é alterada, o algoritmo diff mantém a associação entre instâncias de <DetailsEditor> e person instâncias:When the People collection changes, the diffing algorithm retains the association between <DetailsEditor> instances and person instances:

  • Se uma Person for excluída da lista de People, somente a instância <DetailsEditor> correspondente será removida da interface do usuário.If a Person is deleted from the People list, only the corresponding <DetailsEditor> instance is removed from the UI. Outras instâncias permanecem inalteradas.Other instances are left unchanged.
  • Se uma Person for inserida em alguma posição na lista, uma nova instância de <DetailsEditor> será inserida na posição correspondente.If a Person is inserted at some position in the list, one new <DetailsEditor> instance is inserted at that corresponding position. Outras instâncias permanecem inalteradas.Other instances are left unchanged.
  • Se Person entradas forem reordenadas, as instâncias de <DetailsEditor> correspondentes serão preservadas e reordenadas na interface do usuário.If Person entries are re-ordered, the corresponding <DetailsEditor> instances are preserved and re-ordered in the UI.

Em alguns cenários, o uso de @key minimiza a complexidade de rerenderização e evita possíveis problemas com partes com estado da alteração do DOM, como a posição do foco.In some scenarios, use of @key minimizes the complexity of rerendering and avoids potential issues with stateful parts of the DOM changing, such as focus position.

Importante

As chaves são locais para cada elemento ou componente de contêiner.Keys are local to each container element or component. As chaves não são comparadas globalmente ao longo do documento.Keys aren't compared globally across the document.

Quando usar @chaveWhen to use @key

Normalmente, faz sentido usar @key sempre que uma lista é renderizada (por exemplo, em um bloco de @foreach) e um valor adequado existe para definir o @key.Typically, it makes sense to use @key whenever a list is rendered (for example, in a @foreach block) and a suitable value exists to define the @key.

Você também pode usar @key para impedir Blazor de preservar uma subárvore de elemento ou componente quando um objeto for alterado:You can also use @key to prevent Blazor from preserving an element or component subtree when an object changes:

<div @key="currentPerson">
    ... content that depends on currentPerson ...
</div>

Se @currentPerson for alterado, a diretiva de atributo @key forçará Blazor a descartar toda a <div> e seus descendentes e recriará a subárvore dentro da interface do usuário com novos elementos e componentes.If @currentPerson changes, the @key attribute directive forces Blazor to discard the entire <div> and its descendants and rebuild the subtree within the UI with new elements and components. Isso pode ser útil se você precisar garantir que nenhum estado da interface do usuário seja preservado quando @currentPerson for alterado.This can be useful if you need to guarantee that no UI state is preserved when @currentPerson changes.

Quando não usar @chaveWhen not to use @key

Há um custo de desempenho ao comparar com @key.There's a performance cost when diffing with @key. O custo de desempenho não é grande, mas só especifique @key se o controle das regras de preservação de elemento ou componente beneficiar o aplicativo.The performance cost isn't large, but only specify @key if controlling the element or component preservation rules benefit the app.

Mesmo que @key não seja usado, Blazor preserva as instâncias de elemento filho e de componente o máximo possível.Even if @key isn't used, Blazor preserves child element and component instances as much as possible. A única vantagem de usar @key é o controle sobre como as instâncias de modelo são mapeadas para as instâncias de componente preservadas, em vez do algoritmo diff, selecionando o mapeamento.The only advantage to using @key is control over how model instances are mapped to the preserved component instances, instead of the diffing algorithm selecting the mapping.

Quais valores usar para @chaveWhat values to use for @key

Geralmente, faz sentido fornecer um dos seguintes tipos de valor para @key:Generally, it makes sense to supply one of the following kinds of value for @key:

  • Instâncias de objeto de modelo (por exemplo, uma instância de Person como no exemplo anterior).Model object instances (for example, a Person instance as in the earlier example). Isso garante a preservação com base na igualdade de referência de objeto.This ensures preservation based on object reference equality.
  • Identificadores exclusivos (por exemplo, valores de chave primária do tipo int, stringou Guid).Unique identifiers (for example, primary key values of type int, string, or Guid).

Verifique se os valores usados para @key não estão em conflito.Ensure that values used for @key don't clash. Se valores conflitantes forem detectados dentro do mesmo elemento pai, Blazor lançará uma exceção porque ele não pode mapear de forma determinística elementos ou componentes antigos para novos elementos ou componentes.If clashing values are detected within the same parent element, Blazor throws an exception because it can't deterministically map old elements or components to new elements or components. Use apenas valores distintos, como instâncias de objeto ou valores de chave primária.Only use distinct values, such as object instances or primary key values.

RoteamentoRouting

O roteamento no Blazor é obtido fornecendo um modelo de rota para cada componente acessível no aplicativo.Routing in Blazor is achieved by providing a route template to each accessible component in the app.

Quando um arquivo Razor com uma diretiva @page é compilado, a classe gerada recebe um RouteAttribute especificando o modelo de rota.When a Razor file with an @page directive is compiled, the generated class is given a RouteAttribute specifying the route template. Em 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.At runtime, the router looks for component classes with a RouteAttribute and renders whichever component has a route template that matches the requested URL.

Vários modelos de rota podem ser aplicados a um componente.Multiple route templates can be applied to a component. O componente a seguir responde às solicitações de /BlazorRoute e /DifferentBlazorRoute:The following component responds to requests for /BlazorRoute and /DifferentBlazorRoute:

@page "/BlazorRoute"
@page "/DifferentBlazorRoute"

<h1>Blazor routing</h1>

Parâmetros de rotaRoute parameters

Os componentes podem receber parâmetros de rota do modelo de rota fornecido na diretiva @page.Components can receive route parameters from the route template provided in the @page directive. O roteador usa parâmetros de rota para preencher os parâmetros de componente correspondentes.The router uses route parameters to populate the corresponding component parameters.

Componente de parâmetro de rota:Route Parameter component:

@page "/RouteParameter"
@page "/RouteParameter/{text}"

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

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

    protected override void OnInitialized()
    {
        Text = Text ?? "fantastic";
    }
}

Não há suporte para parâmetros opcionais, portanto, duas diretivas @page são aplicadas no exemplo acima.Optional parameters aren't supported, so two @page directives are applied in the example above. O primeiro permite a navegação para o componente sem um parâmetro.The first permits navigation to the component without a parameter. A segunda diretiva de @page usa o parâmetro {text} Route e atribui o valor à propriedade Text.The second @page directive takes the {text} route parameter and assigns the value to the Text property.

A sintaxe de parâmetro catch-all (*/**), que captura o caminho entre vários limites de pasta, não tem suporte em componentes do Razor ( . Razor).Catch-all parameter syntax (*/**), which captures the path across multiple folder boundaries, is not supported in Razor components (.razor).

Suporte de classe parcialPartial class support

Os componentes do Razor são gerados como classes parciais.Razor components are generated as partial classes. Os componentes do Razor são criados usando uma das seguintes abordagens:Razor components are authored using either of the following approaches:

  • C#o código é definido em um bloco de @code com marcação HTML e código do Razor em um único arquivo.C# code is defined in an @code block with HTML markup and Razor code in a single file. Blazor modelos definem seus componentes do Razor usando essa abordagem. templates define their Razor components using this approach.
  • C#o código é colocado em um arquivo code-behind definido como uma classe parcial.C# code is placed in a code-behind file defined as a partial class.

O exemplo a seguir mostra o componente de Counter padrão com um bloco de @code em um aplicativo gerado por meio de um modelo de Blazor.The following example shows the default Counter component with an @code block in an app generated from a Blazor template. Marcação HTML, código do Razor e C# código estão no mesmo arquivo:HTML markup, Razor code, and C# code are in the same file:

Counter. Razor:Counter.razor:

@page "/counter"

<h1>Counter</h1>

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

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

@code {
    int currentCount = 0;

    void IncrementCount()
    {
        currentCount++;
    }
}

O componente Counter também pode ser criado usando um arquivo code-behind com uma classe parcial:The Counter component can also be created using a code-behind file with a partial class:

Counter. Razor:Counter.razor:

@page "/counter"

<h1>Counter</h1>

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

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

Counter.Razor.cs:Counter.razor.cs:

namespace BlazorApp.Pages
{
    public partial class Counter
    {
        int currentCount = 0;

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

Especificar uma classe base de componenteSpecify a component base class

A diretiva @inherits pode ser usada para especificar uma classe base para um componente.The @inherits directive can be used to specify a base class for a component.

O aplicativo de exemplo mostra como um componente pode herdar uma classe base, BlazorRocksBase, para fornecer as propriedades e os métodos do componente.The sample app shows how a component can inherit a base class, BlazorRocksBase, to provide the component's properties and methods.

Páginas/BlazorRocks. Razor:Pages/BlazorRocks.razor:

@page "/BlazorRocks"
@inherits BlazorRocksBase

<h1>@BlazorRocksText</h1>

BlazorRocksBase.cs:BlazorRocksBase.cs:

using Microsoft.AspNetCore.Components;

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

A classe base deve derivar de ComponentBase.The base class should derive from ComponentBase.

Importar componentesImport components

O namespace de um componente criado com o Razor baseia-se em (em ordem de prioridade):The namespace of a component authored with Razor is based on (in priority order):

  • @namespace designação na marcação de arquivo Razor ( . Razor) (@namespace BlazorSample.MyNamespace).@namespace designation in Razor file (.razor) markup (@namespace BlazorSample.MyNamespace).
  • O RootNamespace do projeto no arquivo de projeto (<RootNamespace>BlazorSample</RootNamespace>).The project's RootNamespace in the project file (<RootNamespace>BlazorSample</RootNamespace>).
  • O nome do projeto, obtido do nome do arquivo do projeto ( . csproj) e o caminho da raiz do projeto para o componente.The project name, taken from the project file's file name (.csproj), and the path from the project root to the component. Por exemplo, a estrutura resolve {raiz do projeto}/pages/index.Razor (BlazorSample. csproj) para o namespace BlazorSample.Pages.For example, the framework resolves {PROJECT ROOT}/Pages/Index.razor (BlazorSample.csproj) to the namespace BlazorSample.Pages. Os componentes C# seguem regras de associação de nome.Components follow C# name binding rules. Para o componente Index neste exemplo, os componentes no escopo são todos os componentes:For the Index component in this example, the components in scope are all of the components:
    • Na mesma pasta, páginas.In the same folder, Pages.
    • Os componentes na raiz do projeto que não especificam explicitamente um namespace diferente.The components in the project's root that don't explicitly specify a different namespace.

Os componentes definidos em um namespace diferente são trazidos para o escopo usando a diretiva @using do Razor.Components defined in a different namespace are brought into scope using Razor's @using directive.

Se outro componente, NavMenu.razor, existir na pasta BlazorSample/Shared/ , o componente poderá ser usado em Index.razor com a seguinte instrução @using:If another component, NavMenu.razor, exists in the BlazorSample/Shared/ folder, the component can be used in Index.razor with the following @using statement:

@using BlazorSample.Shared

This is the Index page.

<NavMenu></NavMenu>

Os componentes também podem ser referenciados usando seus nomes totalmente qualificados, o que não requer a diretiva @using :Components can also be referenced using their fully qualified names, which doesn't require the @using directive:

This is the Index page.

<BlazorSample.Shared.NavMenu></BlazorSample.Shared.NavMenu>

Observação

Não há suporte para a qualificação de global::.The global:: qualification isn't supported.

Não há suporte para a importação de componentes com instruções de using com alias (por exemplo, @using Foo = Bar).Importing components with aliased using statements (for example, @using Foo = Bar) isn't supported.

Não há suporte para nomes parcialmente qualificados.Partially qualified names aren't supported. Por exemplo, não há suporte para a adição de @using BlazorSample e referência NavMenu.razor com <Shared.NavMenu></Shared.NavMenu>.For example, adding @using BlazorSample and referencing NavMenu.razor with <Shared.NavMenu></Shared.NavMenu> isn't supported.

Atributos de elemento HTML condicionalConditional HTML element attributes

Os atributos de elemento HTML são processados condicionalmente com base no valor do .NET.HTML element attributes are conditionally rendered based on the .NET value. Se o valor for false ou null, o atributo não será renderizado.If the value is false or null, the attribute isn't rendered. Se o valor é true, o atributo é processado minimizado.If the value is true, the attribute is rendered minimized.

No exemplo a seguir, IsCompleted determina se checked é renderizado na marcação do elemento:In the following example, IsCompleted determines if checked is rendered in the element's markup:

<input type="checkbox" checked="@IsCompleted" />

@code {
    [Parameter]
    public bool IsCompleted { get; set; }
}

Se IsCompleted for true, a caixa de seleção será renderizada como:If IsCompleted is true, the check box is rendered as:

<input type="checkbox" checked />

Se IsCompleted for false, a caixa de seleção será renderizada como:If IsCompleted is false, the check box is rendered as:

<input type="checkbox" />

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

Aviso

Alguns atributos HTML, como pressionados pelo Aria, não funcionam corretamente quando o tipo .net é um bool.Some HTML attributes, such as aria-pressed, don't function properly when the .NET type is a bool. Nesses casos, use um tipo de string em vez de um bool.In those cases, use a string type instead of a bool.

HTML brutoRaw HTML

Normalmente, as cadeias de caracteres são renderizadas usando nós de texto DOM, o que significa que qualquer marcação que ela possa conter será ignorada e tratada como texto literal.Strings are normally rendered using DOM text nodes, which means that any markup they may contain is ignored and treated as literal text. Para renderizar HTML bruto, empacote o conteúdo HTML em um valor MarkupString.To render raw HTML, wrap the HTML content in a MarkupString value. O valor é analisado como HTML ou SVG e inserido no DOM.The value is parsed as HTML or SVG and inserted into the DOM.

Aviso

O processamento de HTML bruto construído a partir de qualquer fonte não confiável é um risco à segurança e deve ser evitado!Rendering raw HTML constructed from any untrusted source is a security risk and should be avoided!

O exemplo a seguir mostra como usar o tipo de MarkupString para adicionar um bloco de conteúdo HTML estático à saída renderizada de um componente:The following example shows using the MarkupString type to add a block of static HTML content to the rendered output of a component:

@((MarkupString)myMarkup)

@code {
    private string myMarkup = 
        "<p class='markup'>This is a <em>markup string</em>.</p>";
}

Componentes de modeloTemplated components

Componentes modelo são componentes que aceitam um ou mais modelos de interface do usuário como parâmetros, que podem ser usados como parte da lógica de renderização do componente.Templated components are components that accept one or more UI templates as parameters, which can then be used as part of the component's rendering logic. Os componentes de modelo permitem que você crie componentes de nível superior que são mais reutilizáveis do que os componentes normais.Templated components allow you to author higher-level components that are more reusable than regular components. Alguns exemplos incluem:A couple of examples include:

  • Um componente de tabela que permite que um usuário especifique modelos para o cabeçalho, as linhas e o rodapé da tabela.A table component that allows a user to specify templates for the table's header, rows, and footer.
  • Um componente de lista que permite que um usuário especifique um modelo para renderizar itens em uma lista.A list component that allows a user to specify a template for rendering items in a list.

Parâmetros do ModeloTemplate parameters

Um componente modelo é definido especificando um ou mais parâmetros de componente do tipo RenderFragment ou RenderFragment<T>.A templated component is defined by specifying one or more component parameters of type RenderFragment or RenderFragment<T>. Um fragmento de renderização representa um segmento de interface do usuário a ser renderizado.A render fragment represents a segment of UI to render. RenderFragment<T> usa um parâmetro de tipo que pode ser especificado quando o fragmento de renderização é invocado.RenderFragment<T> takes a type parameter that can be specified when the render fragment is invoked.

TableTemplate componente:TableTemplate component:

@typeparam TItem

<table class="table">
    <thead>
        <tr>@TableHeader</tr>
    </thead>
    <tbody>
        @foreach (var item in Items)
        {
            <tr>@RowTemplate(item)</tr>
        }
    </tbody>
    <tfoot>
        <tr>@TableFooter</tr>
    </tfoot>
</table>

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

    [Parameter]
    public RenderFragment<TItem> RowTemplate { get; set; }

    [Parameter]
    public RenderFragment TableFooter { get; set; }

    [Parameter]
    public IReadOnlyList<TItem> Items { get; set; }
}

Ao usar um componente modelo, os parâmetros do modelo podem ser especificados usando elementos filho que correspondem aos nomes dos parâmetros (TableHeader e RowTemplate no exemplo a seguir):When using a templated component, the template parameters can be specified using child elements that match the names of the parameters (TableHeader and RowTemplate in the following example):

<TableTemplate Items="pets">
    <TableHeader>
        <th>ID</th>
        <th>Name</th>
    </TableHeader>
    <RowTemplate>
        <td>@context.PetId</td>
        <td>@context.Name</td>
    </RowTemplate>
</TableTemplate>

Parâmetros de contexto de modeloTemplate context parameters

Os argumentos de componente do tipo RenderFragment<T> passados como elementos têm um parâmetro implícito denominado context (por exemplo, do exemplo de código anterior, @context.PetId), mas você pode alterar o nome do parâmetro usando o atributo Context no elemento filho.Component arguments of type RenderFragment<T> passed as elements have an implicit parameter named context (for example from the preceding code sample, @context.PetId), but you can change the parameter name using the Context attribute on the child element. No exemplo a seguir, o atributo Context do elemento RowTemplate especifica o parâmetro pet:In the following example, the RowTemplate element's Context attribute specifies the pet parameter:

<TableTemplate Items="pets">
    <TableHeader>
        <th>ID</th>
        <th>Name</th>
    </TableHeader>
    <RowTemplate Context="pet">
        <td>@pet.PetId</td>
        <td>@pet.Name</td>
    </RowTemplate>
</TableTemplate>

Como alternativa, você pode especificar o atributo Context no elemento Component.Alternatively, you can specify the Context attribute on the component element. O atributo Context especificado se aplica a todos os parâmetros de modelo especificados.The specified Context attribute applies to all specified template parameters. Isso pode ser útil quando você deseja especificar o nome do parâmetro de conteúdo para conteúdo filho implícito (sem qualquer elemento filho de disposição).This can be useful when you want to specify the content parameter name for implicit child content (without any wrapping child element). No exemplo a seguir, o atributo Context aparece no elemento TableTemplate e se aplica a todos os parâmetros de modelo:In the following example, the Context attribute appears on the TableTemplate element and applies to all template parameters:

<TableTemplate Items="pets" Context="pet">
    <TableHeader>
        <th>ID</th>
        <th>Name</th>
    </TableHeader>
    <RowTemplate>
        <td>@pet.PetId</td>
        <td>@pet.Name</td>
    </RowTemplate>
</TableTemplate>

Componentes de tipo genéricoGeneric-typed components

Os componentes modelo são geralmente digitados genericamente.Templated components are often generically typed. Por exemplo, um componente de ListViewTemplate genérico pode ser usado para processar IEnumerable<T> valores.For example, a generic ListViewTemplate component can be used to render IEnumerable<T> values. Para definir um componente genérico, use a diretiva @typeparam para especificar parâmetros de tipo:To define a generic component, use the @typeparam directive to specify type parameters:

@typeparam TItem

<ul>
    @foreach (var item in Items)
    {
        @ItemTemplate(item)
    }
</ul>

@code {
    [Parameter]
    public RenderFragment<TItem> ItemTemplate { get; set; }

    [Parameter]
    public IReadOnlyList<TItem> Items { get; set; }
}

Ao usar componentes de tipos genéricos, o parâmetro de tipo é inferido, se possível:When using generic-typed components, the type parameter is inferred if possible:

<ListViewTemplate Items="pets">
    <ItemTemplate Context="pet">
        <li>@pet.Name</li>
    </ItemTemplate>
</ListViewTemplate>

Caso contrário, o parâmetro de tipo deve ser especificado explicitamente usando um atributo que corresponda ao nome do parâmetro de tipo.Otherwise, the type parameter must be explicitly specified using an attribute that matches the name of the type parameter. No exemplo a seguir, TItem="Pet" especifica o tipo:In the following example, TItem="Pet" specifies the type:

<ListViewTemplate Items="pets" TItem="Pet">
    <ItemTemplate Context="pet">
        <li>@pet.Name</li>
    </ItemTemplate>
</ListViewTemplate>

Valores e parâmetros em cascataCascading values and parameters

Em alguns cenários, é inconveniente fluir dados de um componente ancestral para um componente descendente usando parâmetros de componente, especialmente quando há várias camadas de componente.In some scenarios, it's inconvenient to flow data from an ancestor component to a descendent component using component parameters, especially when there are several component layers. Valores e parâmetros em cascata resolvem esse problema fornecendo uma maneira conveniente para um componente ancestral fornecer um valor para todos os seus componentes descendentes.Cascading values and parameters solve this problem by providing a convenient way for an ancestor component to provide a value to all of its descendent components. Valores e parâmetros em cascata também fornecem uma abordagem para que os componentes sejam coordenados.Cascading values and parameters also provide an approach for components to coordinate.

Exemplo de temaTheme example

No exemplo a seguir do aplicativo de exemplo, a classe ThemeInfo especifica as informações do tema para fluir para baixo na hierarquia do componente para que todos os botões de uma determinada parte do aplicativo compartilhem o mesmo estilo.In the following example from the sample app, the ThemeInfo class specifies the theme information to flow down the component hierarchy so that all of the buttons within a given part of the app share the same style.

UIThemeClasses/ThemeInfo.cs:UIThemeClasses/ThemeInfo.cs:

public class ThemeInfo
{
    public string ButtonClass { get; set; }
}

Um componente ancestral pode fornecer um valor em cascata usando o componente de valor em cascata.An ancestor component can provide a cascading value using the Cascading Value component. O componente CascadingValue encapsula uma subárvore da hierarquia de componentes e fornece um único valor para todos os componentes dentro dessa subárvore.The CascadingValue component wraps a subtree of the component hierarchy and supplies a single value to all components within that subtree.

Por exemplo, o aplicativo de exemplo especifica informações de tema (ThemeInfo) em um dos layouts do aplicativo como um parâmetro em cascata para todos os componentes que compõem o corpo do layout da propriedade @Body.For example, the sample app specifies theme information (ThemeInfo) in one of the app's layouts as a cascading parameter for all components that make up the layout body of the @Body property. ButtonClass é atribuído um valor de btn-success no componente de layout.ButtonClass is assigned a value of btn-success in the layout component. Qualquer componente descendente pode consumir essa propriedade por meio do ThemeInfo objeto em cascata.Any descendent component can consume this property through the ThemeInfo cascading object.

CascadingValuesParametersLayout componente:CascadingValuesParametersLayout component:

@inherits LayoutComponentBase
@using BlazorSample.UIThemeClasses

<div class="container-fluid">
    <div class="row">
        <div class="col-sm-3">
            <NavMenu />
        </div>
        <div class="col-sm-9">
            <CascadingValue Value="theme">
                <div class="content px-4">
                    @Body
                </div>
            </CascadingValue>
        </div>
    </div>
</div>

@code {
    private ThemeInfo theme = new ThemeInfo { ButtonClass = "btn-success" };
}

Para fazer uso de valores em cascata, os componentes declaram parâmetros em cascata usando o atributo [CascadingParameter].To make use of cascading values, components declare cascading parameters using the [CascadingParameter] attribute. Os valores em cascata são associados a parâmetros em cascata por tipo.Cascading values are bound to cascading parameters by type.

No aplicativo de exemplo, o componente CascadingValuesParametersTheme associa o valor de ThemeInfo em cascata a um parâmetro em cascata.In the sample app, the CascadingValuesParametersTheme component binds the ThemeInfo cascading value to a cascading parameter. O parâmetro é usado para definir a classe CSS para um dos botões exibidos pelo componente.The parameter is used to set the CSS class for one of the buttons displayed by the component.

CascadingValuesParametersTheme componente:CascadingValuesParametersTheme component:

@page "/cascadingvaluesparameterstheme"
@layout CascadingValuesParametersLayout
@using BlazorSample.UIThemeClasses

<h1>Cascading Values & Parameters</h1>

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

<p>
    <button class="btn" @onclick="IncrementCount">
        Increment Counter (Unthemed)
    </button>
</p>

<p>
    <button class="btn @ThemeInfo.ButtonClass" @onclick="IncrementCount">
        Increment Counter (Themed)
    </button>
</p>

@code {
    private int currentCount = 0;

    [CascadingParameter]
    protected ThemeInfo ThemeInfo { get; set; }

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

Para propagar vários valores do mesmo tipo dentro da mesma subárvore, forneça uma cadeia de caracteres Name exclusiva para cada componente CascadingValue e sua CascadingParametercorrespondente.To cascade multiple values of the same type within the same subtree, provide a unique Name string to each CascadingValue component and its corresponding CascadingParameter. No exemplo a seguir, dois componentes CascadingValue em cascata diferentes instâncias de MyCascadingType por nome:In the following example, two CascadingValue components cascade different instances of MyCascadingType by name:

<CascadingValue Value=@ParentCascadeParameter1 Name="CascadeParam1">
    <CascadingValue Value=@ParentCascadeParameter2 Name="CascadeParam2">
        ...
    </CascadingValue>
</CascadingValue>

@code {
    private MyCascadingType ParentCascadeParameter1;

    [Parameter]
    public MyCascadingType ParentCascadeParameter2 { get; set; }

    ...
}

Em um componente descendente, os parâmetros em cascata recebem seus valores dos valores em cascata correspondentes no componente ancestral por nome:In a descendant component, the cascaded parameters receive their values from the corresponding cascaded values in the ancestor component by name:

...

@code {
    [CascadingParameter(Name = "CascadeParam1")]
    protected MyCascadingType ChildCascadeParameter1 { get; set; }
    
    [CascadingParameter(Name = "CascadeParam2")]
    protected MyCascadingType ChildCascadeParameter2 { get; set; }
}

Exemplo de TabSetTabSet example

Os parâmetros em cascata também permitem que os componentes colaborem na hierarquia do componente.Cascading parameters also enable components to collaborate across the component hierarchy. Por exemplo, considere o exemplo de TabSet a seguir no aplicativo de exemplo.For example, consider the following TabSet example in the sample app.

O aplicativo de exemplo tem uma interface ITab que as guias implementam:The sample app has an ITab interface that tabs implement:

using Microsoft.AspNetCore.Components;

namespace BlazorSample.UIInterfaces
{
    public interface ITab
    {
        RenderFragment ChildContent { get; }
    }
}

O componente CascadingValuesParametersTabSet usa o componente TabSet, que contém vários componentes Tab:The CascadingValuesParametersTabSet component uses the TabSet component, which contains several Tab components:

<TabSet>
    <Tab Title="First tab">
        <h4>Greetings from the first tab!</h4>

        <label>
            <input type="checkbox" @bind="showThirdTab" />
            Toggle third tab
        </label>
    </Tab>
    <Tab Title="Second tab">
        <h4>The second tab says Hello World!</h4>
    </Tab>

    @if (showThirdTab)
    {
        <Tab Title="Third tab">
            <h4>Welcome to the disappearing third tab!</h4>
            <p>Toggle this tab from the first tab.</p>
        </Tab>
    }
</TabSet>

Os componentes de Tab filhos não são passados explicitamente como parâmetros para o TabSet.The child Tab components aren't explicitly passed as parameters to the TabSet. Em vez disso, os componentes de Tab filhos fazem parte do conteúdo filho do TabSet.Instead, the child Tab components are part of the child content of the TabSet. No entanto, o TabSet ainda precisa saber sobre cada componente Tab para que ele possa renderizar os cabeçalhos e a guia ativa. Para habilitar essa coordenação sem a necessidade de código adicional, o componente TabSet pode fornecer a si mesmo como um valor em cascata que é então coletado pelos componentes do Tab descendente.However, the TabSet still needs to know about each Tab component so that it can render the headers and the active tab. To enable this coordination without requiring additional code, the TabSet component can provide itself as a cascading value that is then picked up by the descendent Tab components.

TabSet componente:TabSet component:

@using BlazorSample.UIInterfaces

<!-- Display the tab headers -->
<CascadingValue Value=this>
    <ul class="nav nav-tabs">
        @ChildContent
    </ul>
</CascadingValue>

<!-- Display body for only the active tab -->
<div class="nav-tabs-body p-4">
    @ActiveTab?.ChildContent
</div>

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

    public ITab ActiveTab { get; private set; }

    public void AddTab(ITab tab)
    {
        if (ActiveTab == null)
        {
            SetActivateTab(tab);
        }
    }

    public void RemoveTab(ITab tab)
    {
        if (ActiveTab == tab)
        {
            SetActivateTab(null);
        }
    }

    public void SetActivateTab(ITab tab)
    {
        if (ActiveTab != tab)
        {
            ActiveTab = tab;
            StateHasChanged();
        }
    }
}

Os componentes Tab descendentes capturam o TabSet recipiente como um parâmetro em cascata, de modo que os componentes Tab se adicionam à TabSet e coordenam em qual guia está ativa.The descendent Tab components capture the containing TabSet as a cascading parameter, so the Tab components add themselves to the TabSet and coordinate on which tab is active.

Tab componente:Tab component:

@using BlazorSample.UIInterfaces
@implements ITab

<li>
    <a @onclick="Activate" class="nav-link @TitleCssClass" role="button">
        @Title
    </a>
</li>

@code {
    [CascadingParameter]
    public TabSet ContainerTabSet { get; set; }

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

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

    private string TitleCssClass => ContainerTabSet.ActiveTab == this ? "active" : null;

    protected override void OnInitialized()
    {
        ContainerTabSet.AddTab(this);
    }

    private void Activate()
    {
        ContainerTabSet.SetActivateTab(this);
    }
}

Modelos do RazorRazor templates

Os fragmentos de renderização podem ser definidos usando a sintaxe de modelo Razor.Render fragments can be defined using Razor template syntax. Os modelos Razor são uma maneira de definir um trecho de interface do usuário e assumir o seguinte formato:Razor templates are a way to define a UI snippet and assume the following format:

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

O exemplo a seguir ilustra como especificar RenderFragment e valores de RenderFragment<T> e renderizar modelos diretamente em um componente.The following example illustrates how to specify RenderFragment and RenderFragment<T> values and render templates directly in a component. Os fragmentos de renderização também podem ser passados como argumentos para componentes de modelo.Render fragments can also be passed as arguments to templated components.

@timeTemplate

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

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

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

Saída renderizada do código anterior:Rendered output of the preceding code:

<p>The time is 10/04/2018 01:26:52.</p>

<p>Your pet's name is Rex.</p>

Lógica RenderTreeBuilder manualManual RenderTreeBuilder logic

Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder fornece métodos para manipular componentes e elementos, incluindo a criação manual de componentes C# no código.Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder provides methods for manipulating components and elements, including building components manually in C# code.

Observação

O uso de RenderTreeBuilder para criar componentes é um cenário avançado.Use of RenderTreeBuilder to create components is an advanced scenario. Um componente malformado (por exemplo, uma marca de marcação não fechada) pode resultar em um comportamento indefinido.A malformed component (for example, an unclosed markup tag) can result in undefined behavior.

Considere o seguinte componente de PetDetails, que pode ser compilado manualmente em outro componente:Consider the following PetDetails component, which can be manually built into another component:

<h2>Pet Details Component</h2>

<p>@PetDetailsQuote</p>

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

No exemplo a seguir, o loop no método CreateComponent gera três componentes PetDetails.In the following example, the loop in the CreateComponent method generates three PetDetails components. Ao chamar RenderTreeBuilder métodos para criar os componentes (OpenComponent e AddAttribute), os números de sequência são números de linha de código-fonte.When calling RenderTreeBuilder methods to create the components (OpenComponent and AddAttribute), sequence numbers are source code line numbers. O algoritmo de diferença de Blazor depende dos números de sequência correspondentes a linhas distintas de código, não a invocações de chamada distintas.The Blazor difference algorithm relies on the sequence numbers corresponding to distinct lines of code, not distinct call invocations. Ao criar um componente com métodos RenderTreeBuilder, codifique os argumentos para números de sequência.When creating a component with RenderTreeBuilder methods, hardcode the arguments for sequence numbers. O uso de um cálculo ou contador para gerar o número de sequência pode levar a um desempenho insatisfatório.Using a calculation or counter to generate the sequence number can lead to poor performance. Para obter mais informações, consulte os números de sequência relacionados à seção números de linha de código e não ordem de execução .For more information, see the Sequence numbers relate to code line numbers and not execution order section.

BuiltContent componente:BuiltContent component:

@page "/BuiltContent"

<h1>Build a component</h1>

@CustomRender

<button type="button" @onclick="RenderComponent">
    Create three Pet Details components
</button>

@code {
    private RenderFragment CustomRender { get; set; }
    
    private RenderFragment CreateComponent() => builder =>
    {
        for (var i = 0; i < 3; i++) 
        {
            builder.OpenComponent(0, typeof(PetDetails));
            builder.AddAttribute(1, "PetDetailsQuote", "Someone's best friend!");
            builder.CloseComponent();
        }
    };    
    
    private void RenderComponent()
    {
        CustomRender = CreateComponent();
    }
}

! ALERTA Os tipos no Microsoft.AspNetCore.Components.RenderTree permitem o processamento dos resultados de operações de renderização.![WARNING] The types in Microsoft.AspNetCore.Components.RenderTree allow processing of the results of rendering operations. Estes são detalhes internos da implementação do Blazor Framework.These are internal details of the Blazor framework implementation. Esses tipos devem ser considerados instáveis e sujeitos a alterações em versões futuras.These types should be considered unstable and subject to change in future releases.

Números de sequência se relacionam a números de linha de código e não a ordem de execuçãoSequence numbers relate to code line numbers and not execution order

Blazor .razor arquivos são sempre compilados. .razor files are always compiled. Isso é potencialmente uma grande vantagem para .razor porque a etapa de compilação pode ser usada para injetar informações que melhoram o desempenho do aplicativo em tempo de execução.This is potentially a great advantage for .razor because the compile step can be used to inject information that improve app performance at runtime.

Um exemplo importante desses aprimoramentos envolve números de sequência.A key example of these improvements involve sequence numbers. Os números de sequência indicam ao tempo de execução que as saídas vieram de quais linhas de código distintas e ordenadas.Sequence numbers indicate to the runtime which outputs came from which distinct and ordered lines of code. O tempo de execução usa essas informações para gerar comparações de árvore eficientes em tempo linear, o que é muito mais rápido do que normalmente é possível para um algoritmo de comparação de árvore geral.The runtime uses this information to generate efficient tree diffs in linear time, which is far faster than is normally possible for a general tree diff algorithm.

Considere o seguinte arquivo de .razor simples:Consider the following simple .razor file:

@if (someFlag)
{
    <text>First</text>
}

Second

O código anterior é compilado para algo semelhante ao seguinte:The preceding code compiles to something like the following:

if (someFlag)
{
    builder.AddContent(0, "First");
}

builder.AddContent(1, "Second");

Quando o código é executado pela primeira vez, se someFlag for true, o Construtor receberá:When the code executes for the first time, if someFlag is true, the builder receives:

SequenceSequence {1>Tipo<1}Type DadosData
00 Nó de textoText node FirstFirst
11 Nó de textoText node SegundoSecond

Imagine que someFlag se torna falsee a marcação é renderizada novamente.Imagine that someFlag becomes false, and the markup is rendered again. Desta vez, o Construtor recebe:This time, the builder receives:

SequenceSequence {1>Tipo<1}Type DadosData
11 Nó de textoText node SegundoSecond

Quando o tempo de execução executa uma comparação, ele vê que o item na sequência 0 foi removido e, portanto, gera o seguinte script de ediçãotrivial:When the runtime performs a diff, it sees that the item at sequence 0 was removed, so it generates the following trivial edit script:

  • Remova o primeiro nó de texto.Remove the first text node.

O que vai errado se você gerar números de sequência programaticamenteWhat goes wrong if you generate sequence numbers programmatically

Imagine, em vez disso, que você escreveu a seguinte lógica do construtor de árvore de renderização:Imagine instead that you wrote the following render tree builder logic:

var seq = 0;

if (someFlag)
{
    builder.AddContent(seq++, "First");
}

builder.AddContent(seq++, "Second");

Agora, a primeira saída é:Now, the first output is:

SequenceSequence {1>Tipo<1}Type DadosData
00 Nó de textoText node FirstFirst
11 Nó de textoText node SegundoSecond

Esse resultado é idêntico ao caso anterior, portanto, não existem problemas negativos.This outcome is identical to the prior case, so no negative issues exist. someFlag é false no segundo processamento e a saída é:someFlag is false on the second rendering, and the output is:

SequenceSequence {1>Tipo<1}Type DadosData
00 Nó de textoText node SegundoSecond

Desta vez, o algoritmo diff vê que duas alterações ocorreram e o algoritmo gera o seguinte script de edição:This time, the diff algorithm sees that two changes have occurred, and the algorithm generates the following edit script:

  • Altere o valor do primeiro nó de texto para Second.Change the value of the first text node to Second.
  • Remova o segundo nó de texto.Remove the second text node.

A geração dos números de sequência perdeu todas as informações úteis sobre onde os if/else branches e loops estavam presentes no código original.Generating the sequence numbers has lost all the useful information about where the if/else branches and loops were present in the original code. Isso resulta em uma comparação duas vezes mais longa do que antes.This results in a diff twice as long as before.

Esse é um exemplo trivial.This is a trivial example. Em casos mais realistas com estruturas complexas e profundamente aninhadas, e especialmente com loops, o custo de desempenho é mais grave.In more realistic cases with complex and deeply nested structures, and especially with loops, the performance cost is more severe. Em vez de identificar imediatamente quais blocos de loop ou ramificações foram inseridos ou removidos, o algoritmo diff precisa recorrer profundamente nas árvores de renderização e geralmente criar scripts de edição muito mais, pois ele é informado indiretamente sobre como as estruturas antigas e novas relacionar entre si.Instead of immediately identifying which loop blocks or branches have been inserted or removed, the diff algorithm has to recurse deeply into the render trees and usually build far longer edit scripts because it is misinformed about how the old and new structures relate to each other.

Diretrizes e conclusõesGuidance and conclusions

  • O desempenho do aplicativo será afetado se os números de sequência forem gerados dinamicamente.App performance suffers if sequence numbers are generated dynamically.
  • A estrutura não pode criar seus próprios números de sequência automaticamente em tempo de execução porque as informações necessárias não existem, a menos que sejam capturadas no momento da compilação.The framework can't create its own sequence numbers automatically at runtime because the necessary information doesn't exist unless it's captured at compile time.
  • Não grave blocos longos de lógica de RenderTreeBuilder implementada manualmente.Don't write long blocks of manually-implemented RenderTreeBuilder logic. Prefira .razor arquivos e permitir que o compilador lide com os números de sequência.Prefer .razor files and allow the compiler to deal with the sequence numbers. Se você não conseguir evitar a lógica de RenderTreeBuilder manual, divida blocos longos de código em partes menores encapsuladas em chamadas OpenRegion/CloseRegion.If you're unable to avoid manual RenderTreeBuilder logic, split long blocks of code into smaller pieces wrapped in OpenRegion/CloseRegion calls. Cada região tem seu próprio espaço separado de números de sequência, para que você possa reiniciar de zero (ou qualquer outro número arbitrário) dentro de cada região.Each region has its own separate space of sequence numbers, so you can restart from zero (or any other arbitrary number) inside each region.
  • Se os números de sequência forem codificados, o algoritmo diff só exigirá que os números de sequência aumentem de valor.If sequence numbers are hardcoded, the diff algorithm only requires that sequence numbers increase in value. O valor inicial e as lacunas são irrelevantes.The initial value and gaps are irrelevant. Uma opção legítima é usar o número de linha de código como o número de sequência, ou começar de zero e aumentar por um ou centenas (ou qualquer intervalo preferencial).One legitimate option is to use the code line number as the sequence number, or start from zero and increase by ones or hundreds (or any preferred interval).
  • Blazor usa números de sequência, enquanto outras estruturas de interface do usuário de diferenciação de árvore não as usam. uses sequence numbers, while other tree-diffing UI frameworks don't use them. A comparação é muito mais rápida quando números de sequência são usados e Blazor tem a vantagem de uma etapa de compilação que lida com números de sequência automaticamente para desenvolvedores que criam arquivos . Razor .Diffing is far faster when sequence numbers are used, and Blazor has the advantage of a compile step that deals with sequence numbers automatically for developers authoring .razor files.

LocalizaçãoLocalization

os aplicativos do Blazor Server são localizados usando o middleware de localização.Blazor Server apps are localized using Localization Middleware. O middleware seleciona a cultura apropriada para os usuários que solicitam recursos do aplicativo.The middleware selects the appropriate culture for users requesting resources from the app.

A cultura pode ser definida usando uma das seguintes abordagens:The culture can be set using one of the following approaches:

Para obter mais informações e exemplos, consulte Globalização e localização no ASP.NET Core.For more information and examples, see Globalização e localização no ASP.NET Core.

Configurar o vinculador para internacionalização (Blazor Webassembly)Configure the linker for internationalization (Blazor WebAssembly)

Por padrão, a configuração do vinculador Blazorpara aplicativos Webassembly Blazor retira informações de internacionalização, exceto as localidades explicitamente solicitadas.By default, Blazor's linker configuration for Blazor WebAssembly apps strips out internationalization information except for locales explicitly requested. Para obter mais informações e orientação sobre como controlar o comportamento do vinculador, consulte Configurar o vinculador para ASP.NET Core Blazor.For more information and guidance on controlling the linker's behavior, see Configurar o vinculador para ASP.NET Core Blazor.

CookiesCookies

Um cookie de cultura de localização pode persistir a cultura do usuário.A localization culture cookie can persist the user's culture. O cookie é criado pelo método OnGet da página host do aplicativo (pages/host. cshtml. cs).The cookie is created by the OnGet method of the app's host page (Pages/Host.cshtml.cs). O middleware de localização lê o cookie em solicitações subsequentes para definir a cultura do usuário.The Localization Middleware reads the cookie on subsequent requests to set the user's culture.

O uso de um cookie garante que a conexão WebSocket possa propagar corretamente a cultura.Use of a cookie ensures that the WebSocket connection can correctly propagate the culture. Se os esquemas de localização forem baseados no caminho da URL ou na cadeia de caracteres de consulta, o esquema pode não ser capaz de trabalhar com WebSockets, portanto, falha ao persistir a cultura.If localization schemes are based on the URL path or query string, the scheme might not be able to work with WebSockets, thus fail to persist the culture. Portanto, o uso de um cookie de cultura de localização é a abordagem recomendada.Therefore, use of a localization culture cookie is the recommended approach.

Qualquer técnica pode ser usada para atribuir uma cultura se a cultura persistir em um cookie de localização.Any technique can be used to assign a culture if the culture is persisted in a localization cookie. Se o aplicativo já tiver um esquema de localização estabelecido para ASP.NET Core do lado do servidor, continue a usar a infraestrutura de localização existente do aplicativo e defina o cookie de cultura de localização no esquema do aplicativo.If the app already has an established localization scheme for server-side ASP.NET Core, continue to use the app's existing localization infrastructure and set the localization culture cookie within the app's scheme.

O exemplo a seguir mostra como definir a cultura atual em um cookie que pode ser lido pelo middleware de localização.The following example shows how to set the current culture in a cookie that can be read by the Localization Middleware. Crie um arquivo pages/host. cshtml. cs com o seguinte conteúdo no aplicativo Blazor Server:Create a Pages/Host.cshtml.cs file with the following contents in the Blazor Server app:

public class HostModel : PageModel
{
    public void OnGet()
    {
        HttpContext.Response.Cookies.Append(
            CookieRequestCultureProvider.DefaultCookieName,
            CookieRequestCultureProvider.MakeCookieValue(
                new RequestCulture(
                    CultureInfo.CurrentCulture,
                    CultureInfo.CurrentUICulture)));
    }
}

A localização é manipulada no aplicativo:Localization is handled in the app:

  1. O navegador envia uma solicitação HTTP inicial para o aplicativo.The browser sends an initial HTTP request to the app.
  2. A cultura é atribuída pelo middleware de localização.The culture is assigned by the Localization Middleware.
  3. O método OnGet em _Host. cshtml. cs persiste a cultura em um cookie como parte da resposta.The OnGet method in _Host.cshtml.cs persists the culture in a cookie as part of the response.
  4. O navegador abre uma conexão WebSocket para criar uma sessão interativa do Blazor Server.The browser opens a WebSocket connection to create an interactive Blazor Server session.
  5. O middleware de localização lê o cookie e atribui a cultura.The Localization Middleware reads the cookie and assigns the culture.
  6. A sessão do Blazor Server começa com a cultura correta.The Blazor Server session begins with the correct culture.

Fornecer interface do usuário para escolher a culturaProvide UI to choose the culture

Para fornecer à interface do usuário a fim de permitir a seleção de uma cultura, é recomendável uma abordagem baseada em redirecionamento .To provide UI to allow a user to select a culture, a redirect-based approach is recommended. O processo é semelhante ao que acontece em um aplicativo Web quando um usuário tenta acessar um recurso seguro—o usuário é redirecionado para uma página de entrada e, em seguida, Redirecionado de volta para o recurso original.The process is similar to what happens in a web app when a user attempts to access a secure resource—the user is redirected to a sign-in page and then redirected back to the original resource.

O aplicativo persiste a cultura selecionada do usuário por meio de um redirecionamento para um controlador.The app persists the user's selected culture via a redirect to a controller. O controlador define a cultura selecionada do usuário em um cookie e redireciona o usuário de volta para o URI original.The controller sets the user's selected culture into a cookie and redirects the user back to the original URI.

Estabeleça um ponto de extremidade HTTP no servidor para definir a cultura selecionada do usuário em um cookie e execute o redirecionamento de volta para o URI original:Establish an HTTP endpoint on the server to set the user's selected culture in a cookie and perform the redirect back to the original URI:

[Route("[controller]/[action]")]
public class CultureController : Controller
{
    public IActionResult SetCulture(string culture, string redirectUri)
    {
        if (culture != null)
        {
            HttpContext.Response.Cookies.Append(
                CookieRequestCultureProvider.DefaultCookieName,
                CookieRequestCultureProvider.MakeCookieValue(
                    new RequestCulture(culture)));
        }

        return LocalRedirect(redirectUri);
    }
}

Aviso

Use o resultado da ação LocalRedirect para evitar ataques de redirecionamento abertos.Use the LocalRedirect action result to prevent open redirect attacks. Para obter mais informações, consulte Impedir ataques de redirecionamento aberto no ASP.NET Core.For more information, see Impedir ataques de redirecionamento aberto no ASP.NET Core.

O componente a seguir mostra um exemplo de como executar o redirecionamento inicial quando o usuário seleciona uma cultura:The following component shows an example of how to perform the initial redirection when the user selects a culture:

@inject NavigationManager NavigationManager

<h3>Select your language</h3>

<select @onchange="OnSelected">
    <option>Select...</option>
    <option value="en-US">English</option>
    <option value="fr-FR">Français</option>
</select>

@code {
    private double textNumber;

    private void OnSelected(ChangeEventArgs e)
    {
        var culture = (string)e.Value;
        var uri = new Uri(NavigationManager.Uri())
            .GetComponents(UriComponents.PathAndQuery, UriFormat.Unescaped);
        var query = $"?culture={Uri.EscapeDataString(culture)}&" +
            $"redirectUri={Uri.EscapeDataString(uri)}";

        NavigationManager.NavigateTo("/Culture/SetCulture" + query, forceLoad: true);
    }
}

Usar cenários de localização do .NET em aplicativos BlazorUse .NET localization scenarios in Blazor apps

Dentro de aplicativos Blazor, os seguintes cenários de localização e globalização do .NET estão disponíveis:Inside Blazor apps, the following .NET localization and globalization scenarios are available:

  • . Sistema de recursos da rede.NET's resources system
  • Formatação de número e data específicos da culturaCulture-specific number and date formatting

a funcionalidade de @bind do Blazorexecuta a globalização com base na cultura atual do usuário.Blazor's @bind functionality performs globalization based on the user's current culture. Para obter mais informações, consulte a seção ligação de dados .For more information, see the Data binding section.

No momento, há suporte para um conjunto limitado de cenários de localização de ASP.NET Core:A limited set of ASP.NET Core's localization scenarios are currently supported:

  • IStringLocalizer<> tem suporte em aplicativos Blazor.IStringLocalizer<> is supported in Blazor apps.
  • IHtmlLocalizer<>, IViewLocalizer<>e localização de anotações de dados são ASP.NET Core cenários MVC e não têm suporte em aplicativos Blazor.IHtmlLocalizer<>, IViewLocalizer<>, and Data Annotations localization are ASP.NET Core MVC scenarios and not supported in Blazor apps.

Para obter mais informações, consulte Globalização e localização no ASP.NET Core.For more information, see Globalização e localização no ASP.NET Core.

Imagens SVG (gráficos vetoriais escaláveis)Scalable Vector Graphics (SVG) images

Como Blazor renderiza imagens HTML, com suporte para navegador, incluindo imagens SVG (gráficos de vetor escalonáveis) ( . svg), há suporte por meio da marca <img>:Since Blazor renders HTML, browser-supported images, including Scalable Vector Graphics (SVG) images (.svg), are supported via the <img> tag:

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

Da mesma forma, as imagens SVG têm suporte nas regras de CSS de um arquivo de folha de estilos ( . css):Similarly, SVG images are supported in the CSS rules of a stylesheet file (.css):

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

No entanto, a marcação SVG embutida não tem suporte em todos os cenários.However, inline SVG markup isn't supported in all scenarios. Se você posicionar uma marca de <svg> diretamente em um arquivo de componente ( . Razor), a renderização de imagem básica terá suporte, mas muitos cenários avançados ainda não têm suporte.If you place an <svg> tag directly into a component file (.razor), basic image rendering is supported but many advanced scenarios aren't yet supported. Por exemplo, <use> marcas não são respeitadas atualmente e @bind não podem ser usadas com algumas marcas SVG.For example, <use> tags aren't currently respected, and @bind can't be used with some SVG tags. Esperamos abordar essas limitações em uma versão futura.We expect to address these limitations in a future release.

Recursos adicionaisAdditional resources