Udostępnij za pośrednictwem


Składniki aparatu ASP.NET Core Razor

Uwaga

Nie jest to najnowsza wersja tego artykułu. Aby zapoznać się z bieżącą wersją, zapoznaj się z wersją tego artykułu platformy .NET 8.

Ostrzeżenie

Ta wersja ASP.NET Core nie jest już obsługiwana. Aby uzyskać więcej informacji, zobacz .NET i .NET Core Support Policy (Zasady obsługi platformy .NET Core). Aby zapoznać się z bieżącą wersją, zapoznaj się z wersją tego artykułu platformy .NET 8.

Ważne

Te informacje odnoszą się do produktu w wersji wstępnej, który może zostać znacząco zmodyfikowany, zanim zostanie wydany komercyjnie. Firma Microsoft nie udziela żadnych gwarancji, jawnych lub domniemanych, w odniesieniu do informacji podanych w tym miejscu.

Aby zapoznać się z bieżącą wersją, zapoznaj się z wersją tego artykułu platformy .NET 8.

W tym artykule objaśniono, jak tworzyć składniki aparatu Razor i używać ich w aplikacjach platformy Blazor. Obejmuje to wskazówki dotyczące składni, nazewnictwa składników, przestrzeni nazw i parametrów składników aparatu Razor.

Składniki Razor

Blazor aplikacje są tworzone przy użyciu Razor składników, nieformalnie znanych jako Blazor składniki lub tylko składniki. Składnik to samodzielna część interfejsu użytkownika z logiką przetwarzania umożliwiającą zachowania dynamiczne. Składniki mogą być zagnieżdżone, ponownie używane, współużytkowane między projektami i używane w aplikacjach MVC i Razor Pages.

Składniki są renderowane w przechowywanej w pamięci reprezentacji modelu Document Object Model (DOM) przeglądarki nazywanej drzewem renderowania, która służy do aktualizowania interfejsu użytkownika w elastyczny i wydajny sposób.

Chociaż składniki "Razor współdzielą niektóre nazwy z innymi technologiami renderowania zawartości core ASP.NET Core, Razor składniki muszą być rozróżniane od następujących różnych funkcji w ASP.NET Core:

  • Razor widoki, które są stronami znaczników opartymi Razorna aplikacjach MVC.
  • Wyświetl składniki, które służą do renderowania fragmentów zawartości, a nie całych odpowiedzi w Razor aplikacjach Pages i MVC.

Ważne

W przypadku korzystania z elementu Blazor Web Appwiększość przykładowych Blazor składników dokumentacji wymaga interakcyjności do działania i zademonstrowania pojęć omówionych w artykułach. Podczas testowania przykładowego składnika dostarczonego przez artykuł upewnij się, że aplikacja przyjmuje globalną interakcyjność lub składnik przyjmuje tryb renderowania interaktywnego. Więcej informacji na ten temat zawiera tryb renderowania ASP.NET CoreBlazor, który jest kolejnym artykułem w spisie treści po tym artykule.

Klasy składników

Składniki implementuje się przy użyciu kombinacji języka C# i znaczników HTML w plikach składników Razor z rozszerzeniem .razor.

ComponentBase jest klasą bazową składników opisanych przez Razor pliki składników. ComponentBase implementuje najniższą abstrakcję składników — IComponent interfejs. ComponentBase definiuje właściwości i metody składników dla podstawowych funkcji, na przykład w celu przetwarzania zestawu wbudowanych zdarzeń cyklu życia składników.

ComponentBase w dotnet/aspnetcore źródle referencyjnym: Źródło referencyjne zawiera dodatkowe uwagi dotyczące wbudowanych zdarzeń cyklu życia. Należy jednak pamiętać, że wewnętrzne implementacje funkcji składników mogą ulec zmianie w dowolnym momencie bez powiadomienia.

Uwaga

Linki dokumentacji do źródła referencyjnego platformy .NET zwykle ładują domyślną gałąź repozytorium, która odzwierciedla bieżące programowanie dla następnej wersji platformy .NET. Aby wybrać tag dla określonej wersji, użyj listy rozwijanej Przełącz gałęzie lub tagi. Aby uzyskać więcej informacji, zobacz Jak wybrać tag wersji kodu źródłowego platformy ASP.NET Core (dotnet/AspNetCore.Docs #26205).

Deweloperzy zazwyczaj tworzą Razor składniki na podstawie Razor plików składników (.razor) lub bazują na składnikach ComponentBase, ale składniki mogą być również kompilowane przez zaimplementowanie elementu IComponent. Składniki utworzone przez deweloperów, które implementują IComponent , mogą mieć niską kontrolę nad renderowaniem kosztem konieczności ręcznego wyzwalania renderowania przy użyciu zdarzeń i metod cyklu życia, które deweloper musi utworzyć i obsługiwać.

Dodatkowe konwencje przyjęte przez Blazor przykładowy kod dokumentacji i przykładowe aplikacje znajdują się w podstawach ASP.NET CoreBlazor.

Składnia aparatu Razor

Składniki używają składni aparatu Razor. Składniki często używają dwóch funkcji aparatu Razor: dyrektyw i atrybutów dyrektyw. Są to zastrzeżone słowa kluczowe poprzedzone prefiksem @, które występują w znacznikach aparatu Razor:

  • Dyrektywy: Zmiana sposobu kompilowania znaczników składników lub funkcji. Na przykład @page dyrektywa określa składnik routingu z szablonem trasy, który można uzyskać bezpośrednio przez żądanie użytkownika w przeglądarce pod określonym adresem URL.

    Zgodnie z konwencją dyrektywy składnika w górnej części definicji składnika (.razor pliku) są umieszczane w spójnej kolejności. W przypadku powtarzających się dyrektyw dyrektywy są umieszczane alfabetycznie według przestrzeni nazw lub typu, z wyjątkiem @using dyrektyw, które mają specjalne porządkowanie drugiego poziomu.

    Poniższa kolejność jest przyjmowana przez Blazor przykładowe aplikacje i dokumentację. Składniki dostarczane przez Blazor szablon projektu mogą różnić się od poniższej kolejności i używać innego formatu. Na przykład Blazor składniki struktury Identity zawierają puste wiersze między blokami @using dyrektyw i blokami @inject dyrektyw. Możesz używać niestandardowego schematu porządkowania i formatowania we własnych aplikacjach.

    Dokumentacja i przykładowa kolejność dyrektywy aplikacji Razor :

    • @page
    • @rendermode (.NET 8 lub nowszy)
    • @using
      • System przestrzenie nazw (kolejność alfabetyczna)
      • Microsoft przestrzenie nazw (kolejność alfabetyczna)
      • Przestrzenie nazw interfejsu API innych firm (kolejność alfabetyczna)
      • Przestrzenie nazw aplikacji (kolejność alfabetyczna)
    • Inne dyrektywy (kolejność alfabetyczna)

    W dyrektywach nie są wyświetlane żadne puste wiersze. Jeden pusty wiersz pojawia się między dyrektywami a pierwszą linią Razor znaczników.

    Przykład:

    @page "/doctor-who-episodes/{season:int}"
    @rendermode InteractiveWebAssembly
    @using System.Globalization
    @using System.Text.Json
    @using Microsoft.AspNetCore.Localization
    @using Mandrill
    @using BlazorSample.Components.Layout
    @attribute [Authorize]
    @implements IAsyncDisposable
    @inject IJSRuntime JS
    @inject ILogger<DoctorWhoEpisodes> Logger
    
    <PageTitle>Doctor Who Episode List</PageTitle>
    
    ...
    
  • Atrybuty dyrektywy: zmień sposób kompilowania elementu składnika lub funkcji.

    Przykład:

    <input @bind="episodeId" />
    

    Możesz prefiksować wartości atrybutów dyrektywy z symbolem at (@) dla wyrażeń innych niż jawne Razor (@bind="@episodeId"), ale nie zalecamy ich, a dokumenty nie przyjmują podejścia w przykładach.

Dyrektywy i atrybuty dyrektyw używane w składnikach zostały objaśnione szerzej w tym artykule i innych artykułach w zestawie dokumentacji platformy Blazor. Aby uzyskać ogólne informacje o składni aparatu Razor, zobacz Dokumentacja składni aparatu Razor dla platformy ASP.NET Core.

Nazwa składnika, nazwa klasy i przestrzeń nazw

Nazwa składnika musi zaczynać się wielką literą:

Obsługiwane: ProductDetail.razor

Nieobsługiwane: productDetail.razor

Typowe konwencje nazewnictwa platformy Blazor używane w dokumentacji platformy Blazor obejmują:

  • Ścieżki plików i nazwy plików używają wielkości liter Pascal† i pojawiają się przed wyświetleniem przykładów kodu. Jeśli ścieżka jest obecna, wskazuje typową lokalizację folderu. Na przykład wskazuje, Components/Pages/ProductDetail.razor że ProductDetail składnik ma nazwę ProductDetail.razor pliku i znajduje się w Pages folderze Components folderu aplikacji.
  • Ścieżki plików składników dla składników routingu pasują do ich adresów URL w przypadku kebabu} z łącznikami występującymi między wyrazami w szablonie trasy składnika. Na przykład składnik ProductDetail z szablonem trasy /product-detail (@page "/product-detail") jest żądany w przeglądarce pod względnym adresem URL /product-detail.

†Wielkość liter zgodna z językiem Pascal (nazwy z wyrazami pisanymi wielkimi literami) to konwencja nazewnictwa bez spacji i interpunkcji, gdzie każdy wyraz zaczyna się wielką literą, włącznie z pierwszym wyrazem.
{Przypadek Kebab to konwencja nazewnictwa bez spacji i znaków interpunkcyjnych, która używa małych liter i kreski między wyrazami.

Składniki są zwykłymi klasami języka C# i można je umieszczać w dowolnym miejscu w projekcie. Składniki tworzące strony internetowe zazwyczaj znajdują się w folderze Components/Pages. Składniki niezwiązane ze stronami są często umieszczane w folderze Components lub w folderze niestandardowym dodanym do projektu.

Zazwyczaj przestrzeń nazw składnika jest oparta na głównej przestrzeni nazw aplikacji i lokalizacji składnika (folderu) w aplikacji. Jeśli główna przestrzeń nazw aplikacji to BlazorSample, a składnik Counter znajduje się w folderze Components/Pages:

  • Przestrzeń nazw składnika Counter to BlazorSample.Components.Pages.
  • W pełni kwalifikowana nazwa typu składnika to BlazorSample.Components.Pages.Counter.

W przypadku niestandardowych folderów zawierających składniki dodaj dyrektywę @using do składnika nadrzędnego lub do pliku _Imports.razor aplikacji. W poniższym przykładzie są udostępniane składniki w folderze AdminComponents:

@using BlazorSample.AdminComponents

Uwaga

Dyrektywy @using w pliku _Imports.razor są stosowane tylko do plików aparatu Razor (.razor), a nie do plików języka C# (.cs).

Obsługiwane są instrukcje aliasowe using . W poniższym przykładzie publiczna WeatherForecast klasa GridRendering składnika jest udostępniana jako WeatherForecast składnik w innym miejscu w aplikacji:

@using WeatherForecast = Components.Pages.GridRendering.WeatherForecast

Do składników można też odwoływać się przy użyciu ich w pełni kwalifikowanych nazw, co nie wymaga dyrektywy @using. Poniższy przykład bezpośrednio odwołuje się do składnika ProductDetail w folderze AdminComponents/Pages aplikacji:

<BlazorSample.AdminComponents.Pages.ProductDetail />

Przestrzeń nazw składnika tworzona w aparacie Razor jest oparta na następujących elementach (w kolejności priorytetów):

  • Dyrektywa @namespace w znacznikach pliku aparatu Razor (na przykład @namespace BlazorSample.CustomNamespace).
  • Element RootNamespace projektu w pliku projektu (na przykład <RootNamespace>BlazorSample</RootNamespace>).
  • Przestrzeń nazw projektu i ścieżka z katalogu głównego projektu do składnika. Na przykład struktura rozpoznaje {PROJECT NAMESPACE}/Components/Pages/Home.razor przestrzeń BlazorSample nazw projektu w przestrzeni nazw BlazorSample.Components.Pages składnika Home . {PROJECT NAMESPACE} to przestrzeń nazw projektu. Składniki przestrzegają reguł wiązania nazw języka C#. W tym przykładzie Home składniki w zakresie są wszystkimi składnikami:
    • W tym samym folderze (Components/Pages).
    • Składniki w katalogu głównym projektu, które nie określają jawnie innej przestrzeni nazw.

Nie są obsługiwane następujące elementy:

  • Kwalifikowanie global::.
  • Częściowo kwalifikowane nazwy. Na przykład nie można dodać elementu @using BlazorSample.Components do składnika, a następnie odwołać się do składnika NavMenu w folderze Components/Layout aplikacji (Components/Layout/NavMenu.razor) za pomocą elementu <Layout.NavMenu></Layout.NavMenu>.

Nazwa składnika musi zaczynać się wielką literą:

Obsługiwane: ProductDetail.razor

Nieobsługiwane: productDetail.razor

Typowe konwencje nazewnictwa platformy Blazor używane w dokumentacji platformy Blazor obejmują:

  • Ścieżki plików i nazwy plików używają wielkości liter Pascal† i pojawiają się przed wyświetleniem przykładów kodu. Jeśli ścieżka jest obecna, wskazuje typową lokalizację folderu. Na przykład Pages/ProductDetail.razor wskazuje, że składnik ProductDetail ma nazwę pliku ProductDetail.razor i znajduje się w folderze Pages aplikacji.
  • Ścieżki plików składników dla składników routingu pasują do ich adresów URL w przypadku kebabu} z łącznikami występującymi między wyrazami w szablonie trasy składnika. Na przykład składnik ProductDetail z szablonem trasy /product-detail (@page "/product-detail") jest żądany w przeglądarce pod względnym adresem URL /product-detail.

†Wielkość liter zgodna z językiem Pascal (nazwy z wyrazami pisanymi wielkimi literami) to konwencja nazewnictwa bez spacji i interpunkcji, gdzie każdy wyraz zaczyna się wielką literą, włącznie z pierwszym wyrazem.
{Przypadek Kebab to konwencja nazewnictwa bez spacji i znaków interpunkcyjnych, która używa małych liter i kreski między wyrazami.

Składniki są zwykłymi klasami języka C# i można je umieszczać w dowolnym miejscu w projekcie. Składniki tworzące strony internetowe zazwyczaj znajdują się w folderze Pages. Składniki niezwiązane ze stronami są często umieszczane w folderze Shared lub w folderze niestandardowym dodanym do projektu.

Zazwyczaj przestrzeń nazw składnika jest oparta na głównej przestrzeni nazw aplikacji i lokalizacji składnika (folderu) w aplikacji. Jeśli główna przestrzeń nazw aplikacji to BlazorSample, a składnik Counter znajduje się w folderze Pages:

  • Przestrzeń nazw składnika Counter to BlazorSample.Pages.
  • W pełni kwalifikowana nazwa typu składnika to BlazorSample.Pages.Counter.

W przypadku niestandardowych folderów zawierających składniki dodaj dyrektywę @using do składnika nadrzędnego lub do pliku _Imports.razor aplikacji. W poniższym przykładzie są udostępniane składniki w folderze AdminComponents:

@using BlazorSample.AdminComponents

Uwaga

Dyrektywy @using w pliku _Imports.razor są stosowane tylko do plików aparatu Razor (.razor), a nie do plików języka C# (.cs).

Obsługiwane są instrukcje aliasowe using . W poniższym przykładzie publiczna WeatherForecast klasa GridRendering składnika jest udostępniana jako WeatherForecast składnik w innym miejscu w aplikacji:

@using WeatherForecast = Pages.GridRendering.WeatherForecast

Do składników można też odwoływać się przy użyciu ich w pełni kwalifikowanych nazw, co nie wymaga dyrektywy @using. Poniższy przykład bezpośrednio odwołuje się do składnika ProductDetail w folderze Components aplikacji:

<BlazorSample.Components.ProductDetail />

Przestrzeń nazw składnika tworzona w aparacie Razor jest oparta na następujących elementach (w kolejności priorytetów):

  • Dyrektywa @namespace w znacznikach pliku aparatu Razor (na przykład @namespace BlazorSample.CustomNamespace).
  • Element RootNamespace projektu w pliku projektu (na przykład <RootNamespace>BlazorSample</RootNamespace>).
  • Przestrzeń nazw projektu i ścieżka z katalogu głównego projektu do składnika. Na przykład struktura rozpoznaje {PROJECT NAMESPACE}/Pages/Index.razor przestrzeń BlazorSample nazw projektu w przestrzeni nazw BlazorSample.Pages składnika Index . {PROJECT NAMESPACE} to przestrzeń nazw projektu. Składniki przestrzegają reguł wiązania nazw języka C#. W tym przykładzie Index składniki w zakresie są wszystkimi składnikami:
    • W tym samym folderze (Pages).
    • Składniki w katalogu głównym projektu, które nie określają jawnie innej przestrzeni nazw.

Nie są obsługiwane następujące elementy:

  • Kwalifikowanie global::.
  • Częściowo kwalifikowane nazwy. Na przykład nie można dodać elementu @using BlazorSample do składnika, a następnie odwołać się do składnika NavMenu w folderze Shared aplikacji (Shared/NavMenu.razor) za pomocą elementu <Shared.NavMenu></Shared.NavMenu>.

Obsługa klas częściowych

Składniki są generowane jako klasy częściowe języka C# i są tworzone przy użyciu jednej z następujących metod:

  • Pojedynczy plik zawiera kod języka C# zdefiniowany w jednym lub większej liczbie bloków @code, oraz znaczniki HTML i znaczniki aparatu Razor. Szablony projektów platformy Blazor definiują swoje składniki za pomocą takiej metody z użyciem jednego pliku.
  • Kod HTML i znaczniki aparatu Razor są umieszczane w pliku aparatu Razor (.razor). Kod języka C# jest umieszczany w pliku związanym z kodem zdefiniowanym jako klasa częściowa (.cs).

Uwaga

Arkusz stylów składnika, który definiuje style specyficzne dla składnika, jest osobnym plikiem (.css). Izolacja języka CSS na platformie Blazor jest opisana w dalszej części w sekcji Izolacja języka CSS na platformie ASP.NET Core Blazor.

W poniższym przykładzie pokazano domyślny składnik Counter z blokiem @code w aplikacji wygenerowanej z szablonu projektu platformy Blazor. Znaczniki i kod języka C# znajdują się w tym samym pliku. Jest to najczęstsze podejście stosowane do tworzenia składników.

Counter.razor:

@page "/counter"

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

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

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

@code {
    private int currentCount = 0;

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

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

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

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

@code {
    private int currentCount = 0;

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

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

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

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

@code {
    private int currentCount = 0;

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

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

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

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

@code {
    private int currentCount = 0;

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

<h1>Counter</h1>

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

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

@code {
    private int currentCount = 0;

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

<h1>Counter</h1>

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

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

@code {
    private int currentCount = 0;

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

Poniższy Counter składnik dzieli prezentację HTML i Razor znaczniki z kodu języka C# przy użyciu pliku za pomocą kodu z klasą częściową. Dzielenie znaczników z kodu w języku C# jest preferowane przez niektóre organizacje i deweloperów w celu zorganizowania kodu składowego w celu dopasowania ich do sposobu, w jaki wolą pracować. Na przykład ekspert w zakresie interfejsu użytkownika organizacji może pracować nad warstwą prezentacji niezależnie od innego dewelopera pracującego nad logiką języka C# składnika. Takie podejście jest również przydatne podczas pracy z automatycznie generowanym kodem lub generatorami źródłowymi. Aby uzyskać więcej informacji, zobacz Klasy częściowe i metody (Przewodnik programowania w języku C#).

CounterPartialClass.razor:

@page "/counter-partial-class"

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

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

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

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

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

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

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

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

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

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

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

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

<h1>Counter</h1>

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

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

<h1>Counter</h1>

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

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

CounterPartialClass.razor.cs:

namespace BlazorSample.Components.Pages;

public partial class CounterPartialClass
{
    private int currentCount = 0;

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

public partial class CounterPartialClass
{
    private int currentCount = 0;

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

public partial class CounterPartialClass
{
    private int currentCount = 0;

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

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

Dyrektywy @using w pliku _Imports.razor są stosowane tylko do plików aparatu Razor (.razor), a nie do plików języka C# (.cs). Dodaj przestrzenie nazw do pliku klasy częściowej zgodnie z potrzebami.

Typowe przestrzenie nazw używane przez składniki:

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

Typowe przestrzenie nazw obejmują też przestrzeń nazw aplikacji i przestrzeń nazw odpowiadającą folderowi Components aplikacji:

using BlazorSample;
using BlazorSample.Components;

Można również uwzględnić dodatkowe foldery, takie jak Layout folder:

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

Typowe przestrzenie nazw obejmują też przestrzeń nazw aplikacji i przestrzeń nazw odpowiadającą folderowi Shared aplikacji:

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

Typowe przestrzenie nazw obejmują też przestrzeń nazw aplikacji i przestrzeń nazw odpowiadającą folderowi Shared aplikacji:

using BlazorSample;
using BlazorSample.Shared;

Określanie klasy bazowej

Dyrektywa @inherits służy do określania klasy bazowej dla składnika. W przeciwieństwie do używania klas częściowych, które dzielą tylko znaczniki z logiki języka C#, użycie klasy bazowej umożliwia dziedziczenie kodu C# do użycia w grupie składników, które współużytkujące właściwości i metody klasy bazowej. Używanie klas bazowych zmniejsza nadmiarowość kodu w aplikacjach i jest przydatne podczas dostarczania kodu podstawowego z bibliotek klas do wielu aplikacji. Aby uzyskać więcej informacji, zobacz Dziedziczenie w językach C# i .NET.

W poniższym przykładzie klasa bazowa BlazorRocksBase1 pochodzi z klasy ComponentBase.

BlazorRocks1.razor:

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

<PageTitle>Blazor Rocks!</PageTitle>

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

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

<PageTitle>Blazor Rocks!</PageTitle>

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

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

<PageTitle>Blazor Rocks!</PageTitle>

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

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

<PageTitle>Blazor Rocks!</PageTitle>

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

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

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

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

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

<p>
    @BlazorRocksText
</p>

BlazorRocksBase1.cs:

using Microsoft.AspNetCore.Components;

namespace BlazorSample;

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

namespace BlazorSample;

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

namespace BlazorSample;

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

namespace BlazorSample;

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

namespace BlazorSample;

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

namespace BlazorSample;

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

Routing

Routing na platformie Blazor wymaga podania szablonu trasy do każdego dostępnego składnika aplikacji za pomocą dyrektywy @page. Podczas kompilacji pliku aparatu Razor z dyrektywą @page generowana klasa otrzymuje element RouteAttribute określający szablon trasy. W czasie wykonywania router wyszukuje klasy składników z elementem RouteAttribute i renderuje dowolny składnik, który ma szablon trasy zgodny z żądanym adresem URL.

Poniższy HelloWorld składnik używa szablonu /hello-worldtrasy elementu , a renderowana strona internetowa dla składnika jest osiągana pod względnym adresem URL /hello-world.

HelloWorld.razor:

@page "/hello-world"

<PageTitle>Hello World!</PageTitle>

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

<PageTitle>Hello World!</PageTitle>

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

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

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

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

<h1>Hello World!</h1>

Powyższy składnik jest ładowany w przeglądarce pod adresem /hello-world niezależnie od tego, czy dodasz go do nawigacji interfejsu użytkownika aplikacji. Opcjonalnie składniki można dodawać do elementu NavMenu, aby link do danego składnika był widoczny w nawigacji opartej na interfejsie użytkownika aplikacji.

W przypadku poprzedniego HelloWorld składnika można dodać NavLink składnik do NavMenu składnika. Aby uzyskać więcej informacji, w tym opisy składników NavLink i NavMenu, zobacz Routing i nawigacja na platformie ASP.NET Core Blazor.

Narzut

Interfejs użytkownika składnika definiuje się przy użyciu składni aparatu Razor, która obejmuje znaczniki aparatu Razor oraz kod języków C# i HTML. Podczas kompilowania aplikacji klienckiej znaczniki HTML i logika renderowania w języku C# są konwertowane na klasę składnika. Nazwa wygenerowanej klasy jest zgodna z nazwą pliku.

Elementy członkowskie klasy składnika definiuje się w jednym lub większej liczbie bloków @code. W blokach @code stan składnika jest określany i przetwarzany za pomocą języka C#:

  • Inicjatory właściwości i pól.
  • Wartości parametrów z argumentów przekazywanych przez składniki nadrzędne i parametry trasy.
  • Metody obsługi zdarzeń użytkownika, zdarzeń cyklu życia i niestandardowej logiki składników.

Elementy członkowskie składnika są używane w logice renderowania za pomocą wyrażeń języka C# zaczynających się symbolem @. Na przykład pole języka C# jest renderowane przez dodanie prefiksu @ do nazwy pola. Następujący składnik Markup analizuje i renderuje elementy:

  • headingFontStyle dla wartości właściwości CSS font-style elementu nagłówka.
  • headingText dla zawartości elementu nagłówka.

Markup.razor:

@page "/markup"

<PageTitle>Markup</PageTitle>

<h1>Markup Example</h1>

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

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

<PageTitle>Markup</PageTitle>

<h1>Markup Example</h1>

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

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

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

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

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

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

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

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

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

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

Uwaga

Przykłady w dokumentacji platformy Blazor określają modyfikator dostępu private dla prywatnych elementów członkowskich. Zakresem prywatnych elementów członkowskich jest klasa składnika. Jednak język C# przyjmuje modyfikator dostępu private, gdy nie określono modyfikatora dostępu, więc jawne oznaczanie elementów członkowskich elementem „private” we własnym kodzie jest opcjonalne. Aby uzyskać więcej informacji o modyfikatorach dostępu, zobacz Modyfikatory dostępu (Przewodnik po programowaniu w języku C#).

Struktura Blazor przetwarza składnik wewnętrznie jako drzewo renderowania, które jest kombinacją modelu DOM składnika i kaskadowego modelu obiektów arkusza stylów (CSSOM) składnika. Po wstępnym renderowaniu składnika jego drzewo renderowania jest generowane ponownie w odpowiedzi na zdarzenia. Platforma Blazor porównuje nowe drzewo renderowania z poprzednim i stosuje wszelkie modyfikacje modelu DOM przeglądarki w celu wyświetlenia. Aby uzyskać więcej informacji, zobacz Renderowanie składników platformy ASP.NET Core Razor.

W składni aparatu Razor dla struktur sterujących, dyrektyw i atrybutów dyrektyw w języku C# są używane małe litery (przykłady: @if, @code, @bind). Nazwy właściwości zaczynają się wielką literą (przykład: @Body dla elementu LayoutComponentBase.Body).

Metody asynchroniczne (async) nie obsługują zwracania elementu void

Platforma Blazor nie śledzi metod asynchronicznych (async) zwracających element void. Dlatego wyjątki nie są przechwytywane w przypadku zwrócenia elementu void. Należy zawsze zwracać element Task z metod asynchronicznych.

Składniki zagnieżdżone

Składniki mogą zawierać inne składniki przez zadeklarowanie ich przy użyciu składni języka HTML. Znaczniki dotyczące używania składników wyglądają jak tag HTML, w którym nazwa tagu jest typem składnika.

Rozważmy następujący składnik Heading, który może być używany przez inne składniki w celu wyświetlania nagłówka.

Heading.razor:

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

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

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

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

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

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

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

Poniższe znaczniki w składniku HeadingExample renderują powyższy składnik Heading w lokalizacji, w której występuje tag <Heading />.

HeadingExample.razor:

@page "/heading-example"

<PageTitle>Heading</PageTitle>

<h1>Heading Example</h1>

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

<PageTitle>Heading</PageTitle>

<h1>Heading Example</h1>

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

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

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

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

<Heading />

Jeśli składnik zawiera element HTML zaczynający się wielką literą, która nie jest zgodna z żadną nazwą składnika w tej samej przestrzeni nazw, zostanie wyemitowane ostrzeżenie wskazujące, że element ma nieoczekiwaną nazwę. Dodanie dyrektywy @using dla przestrzeni nazw składnika spowoduje, że składnik stanie się dostępny, a ostrzeżenie zniknie. Aby uzyskać więcej informacji, zobacz sekcję Nazwa składnika, Nazwa klasy i Przestrzeń nazw .

Przykładowy składnik Heading przedstawiony w tej sekcji nie ma dyrektywy @page, więc składnik Heading nie jest bezpośrednio dostępny dla użytkownika za pośrednictwem żądania w przeglądarce. Jednak każdy składnik z dyrektywą @page może być zagnieżdżony w innym składniku. Jeśli składnik Heading był bezpośrednio dostępny przez dołączenie elementu @page "/heading" na początku jego pliku aparatu Razor, to będzie renderowany dla żądań przeglądarki zarówno pod adresem /heading, jak i /heading-example.

Parametry składników

Parametry składników przekazują dane do składników i są definiowane za pomocą publicznych właściwości języka C# w klasie składnika z atrybutem [Parameter]. W poniższym przykładzie wbudowany typ referencyjny (System.String) oraz typ referencyjny zdefiniowany przez użytkownika (PanelBody) są przekazywane jako parametry składnika.

PanelBody.cs:

namespace BlazorSample;

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

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

ParameterChild.razor:

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

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

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

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

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

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

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

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

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

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

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

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

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

Ostrzeżenie

Obsługiwane jest podawanie wartości początkowych dla parametrów składników, ale nie należy tworzyć składników zapisujących wartości w swoich własnych parametrach po pierwszym renderowaniu składnika. Aby uzyskać więcej informacji, zobacz Unikanie zastępowania parametrów w programie ASP.NET Core Blazor.

Parametry Title i Body składnika ParameterChild są ustawiane przez argumenty w tagu HTML, który renderuje wystąpienie składnika. Następujący składnik ParameterParent renderuje dwa składniki ParameterChild:

  • Pierwszy składnik ParameterChild jest renderowany bez podawania argumentów parametrów.
  • Drugi składnik ParameterChild otrzymuje wartości elementów Title i Body ze składnika ParameterParent, który używa jawnego wyrażenia języka C# do ustawienia wartości właściwości elementu PanelBody.

Parameter1.razor:

@page "/parameter-1"

<PageTitle>Parameter 1</PageTitle>

<h1>Parameter Example 1</h1>

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

<ParameterChild />

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

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

Parameter1.razor:

@page "/parameter-1"

<PageTitle>Parameter 1</PageTitle>

<h1>Parameter Example 1</h1>

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

<ParameterChild />

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

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

ParameterParent.razor:

@page "/parameter-parent"

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

<ParameterChild />

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

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

ParameterParent.razor:

@page "/parameter-parent"

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

<ParameterChild />

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

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

ParameterParent.razor:

@page "/parameter-parent"

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

<ParameterChild />

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

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

ParameterParent.razor:

@page "/parameter-parent"

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

<ParameterChild />

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

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

Następujące renderowane znaczniki HTML ze składnika ParameterParent pokazują domyślne wartości składnika ParameterChild, gdy składnik ParameterParent nie podaje wartości parametrów składnika. Gdy składnik ParameterParent podaje wartości parametrów składnika, zastępują one wartości domyślne składnika ParameterChild.

Uwaga

Dla przejrzystości renderowane klasy stylów CSS nie są pokazywane w następujących renderowanych znacznikach HTML.

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

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

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

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

Przypisz pole, właściwość lub wynik metody w języku C# do parametru składnika jako wartość atrybutu HTML. Wartość atrybutu może być zwykle dowolnym wyrażeniem języka C#, które jest zgodne z typem parametru. Wartość atrybutu może opcjonalnie prowadzić z zastrzeżonym @ symbolemRazor, ale nie jest wymagana.

Jeśli parametr składnika jest ciągiem typu, wartość atrybutu jest zamiast tego traktowana jako literał ciągu języka C#. Jeśli zamiast tego chcesz określić wyrażenie języka C#, użyj prefiksu @ .

Następujący składnik ParameterParent2 wyświetla cztery wystąpienia powyższego składnika ParameterChild i ustawia ich wartości parametrów Title na:

Cudzysłowy wokół wartości atrybutów parametrów są w większości przypadków opcjonalne, zgodnie ze specyfikacją HTML5. Na przykład jest obsługiwana składnia Value=this zamiast Value="this". Zalecamy jednak używanie cudzysłowów, ponieważ łatwiej jest je zapamiętać i są one powszechnie używane w technologiach opartych na sieci Web.

W przykładach kodu w dokumentacji:

  • Zawsze są używane cudzysłowy. Przykład: Value="this".
  • Nie używaj prefiksu @ z nieliterals, chyba że jest to wymagane. Przykład: Count="ct", gdzie ct jest zmienną typu liczba. Count="@ct" jest prawidłowym podejściem stylistycznym, ale dokumentacja i przykłady nie przyjmują konwencji.
  • Zawsze unikaj @ literałów poza Razor wyrażeniami. Przykład: IsFixed="true". Obejmuje to słowa kluczowe (na przykład this) i null, ale możesz użyć ich, jeśli chcesz. Na przykład instrukcja IsFixed="@true" jest nietypowa, ale jest obsługiwana.

Parameter2.razor:

@page "/parameter-2"

<PageTitle>Parameter 2</PageTitle>

<h1>Parameter Example 2</h1>

<ParameterChild Title="@title" />

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

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

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

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

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

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

Parameter2.razor:

@page "/parameter-2"

<PageTitle>Parameter 2</PageTitle>

<h1>Parameter Example 2</h1>

<ParameterChild Title="@title" />

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

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

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

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

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

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

ParameterParent2.razor:

@page "/parameter-parent-2"

<ParameterChild Title="@title" />

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

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

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

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

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

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

ParameterParent2.razor:

@page "/parameter-parent-2"

<ParameterChild Title="@title" />

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

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

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

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

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

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

ParameterParent2.razor:

@page "/parameter-parent-2"

<ParameterChild Title="@title" />

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

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

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

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

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

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

Uwaga

Podczas przypisywania elementu członkowskiego języka C# do parametru składnika nie prefiksuj atrybutu HTML parametru za pomocą @polecenia .

Correct (Title jest parametrem ciągu, Count jest parametrem typu liczbowego):

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

Odpowiedź nieprawidłowa:

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

W przeciwieństwie do stron aparatu Razor (.cshtml), platforma Blazornie może wykonywać działań asynchronicznych w wyrażeniu aparatu Razor podczas renderowania składnika. Wynika to z tego, że platforma Blazor jest przeznaczona do renderowania interakcyjnych interfejsów użytkownika. W interakcyjnym interfejsie użytkownika ekran musi zawsze coś wyświetlać, więc blokowanie przepływu renderowania nie ma sensu. Zamiast tego działania asynchroniczne są wykonywane podczas jednego z asynchronicznych zdarzeń cyklu życia. Po każdym asynchronicznym zdarzeniu cyklu życia składnik może być renderowany ponownie. Następująca składnia aparatu Razor nie jest obsługiwana:

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

Kod w poprzednim przykładzie generuje błąd kompilatora podczas kompilowania aplikacji:

Operatora „await” można używać tylko w metodzie asynchronicznej. Należy rozważyć oznaczenie tej metody modyfikatorem „async” i zmianę jej zwracanego typu na „Task”.

Aby asynchronicznie uzyskać wartość parametru Title w poprzednim przykładzie, składnik może użyć zdarzenia cyklu życia OnInitializedAsync, jak pokazano w poniższym przykładzie:

<ParameterChild Title="@title" />

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

Aby uzyskać więcej informacji, zobacz Cykl życia składników platformy ASP.NET Core Razor.

Używanie jawnego wyrażenia aparatu Razor w celu połączenia tekstu z wynikiem wyrażenia na potrzeby przypisania do parametru nie jest obsługiwane. Poniższy przykład przedstawia próbę połączenia tekstu „Set by ” z wartością właściwości obiektu. Taka składnia jest obsługiwana na stronie aparatu Razor (.cshtml), ale nie jest poprawna w przypadku przypisania do parametru Title elementu podrzędnego w składniku. Następująca składnia aparatu Razor nie jest obsługiwana:

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

Kod w poprzednim przykładzie generuje błąd kompilatora podczas kompilowania aplikacji:

Atrybuty składników nie obsługują zawartości złożonej (mieszania języka C# i znaczników).

Aby umożliwić przypisanie wartości złożonej, użyj metody, pola lub właściwości. W poniższym przykładzie tekst „Set by ” jest łączony z wartością właściwości obiektu w metodzie języka C# GetTitle:

Parameter3.razor:

@page "/parameter-3"

<PageTitle>Parameter 3</PageTitle>

<h1>Parameter Example 3</h1>

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

@code {
    private PanelData panelData = new();

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

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

Parameter3.razor:

@page "/parameter-3"

<PageTitle>Parameter 3</PageTitle>

<h1>Parameter Example 3</h1>

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

@code {
    private PanelData panelData = new();

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

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

ParameterParent3.razor:

@page "/parameter-parent-3"

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

@code {
    private PanelData panelData = new();

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

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

ParameterParent3.razor:

@page "/parameter-parent-3"

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

@code {
    private PanelData panelData = new();

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

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

ParameterParent3.razor:

@page "/parameter-parent-3"

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

@code {
    private PanelData panelData = new();

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

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

ParameterParent3.razor:

@page "/parameter-parent-3"

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

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

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

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

Aby uzyskać więcej informacji, zobacz Dokumentacja składni aparatu Razor dla platformy ASP.NET Core.

Ostrzeżenie

Obsługiwane jest podawanie wartości początkowych dla parametrów składników, ale nie należy tworzyć składników zapisujących wartości w swoich własnych parametrach po pierwszym renderowaniu składnika. Aby uzyskać więcej informacji, zobacz Unikanie zastępowania parametrów w programie ASP.NET Core Blazor.

Parametry składników powinny być zadeklarowane jako właściwości automatyczne, co oznacza, że nie powinny zawierać niestandardowej logiki w swoich metodach dostępu get i set. Na przykład następująca właściwość StartData jest właściwością automatyczną:

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

Nie umieszczaj logiki niestandardowej w metodach dostępu get i set, ponieważ parametry składników są przeznaczone wyłącznie do używania jako kanał dla składnika nadrzędnego na potrzeby przepływu informacji do składnika podrzędnego. Jeśli metoda dostępu set właściwości składnika podrzędnego zawiera logikę powodującą ponowne renderowanie składnika nadrzędnego, powstaje nieskończona pętla renderowania.

Aby przekształcić otrzymaną wartość parametru:

  • Pozostaw właściwość parametru jako właściwość automatyczną, aby reprezentować dostarczone dane pierwotne.
  • Utwórz inną właściwość lub metodę, aby dostarczyć przekształcone dane na podstawie właściwości parametru.

Zastąp zdarzenie OnParametersSetAsync, aby przekształcać otrzymany parametr za każdym razem po otrzymaniu nowych danych.

Zapisywanie wartości początkowej w parametrze składnika jest obsługiwane, ponieważ przypisania wartości początkowych nie kolidują z automatycznym renderowaniem składników platformy Blazor. Następujące przypisanie bieżącej lokalnej wartości DateTime za pomocą właściwości DateTime.Now do elementu StartData jest poprawną składnią w składniku:

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

Po początkowym przypisaniu właściwości DateTime.Now nie przypisuj wartości do elementu StartData w kodzie dewelopera. Aby uzyskać więcej informacji, zobacz Unikanie zastępowania parametrów w programie ASP.NET Core Blazor.

Zastosuj atrybut [EditorRequired], aby określić wymagany parametr składnika. Jeśli wartość parametru nie zostanie podana, edytory lub narzędzia do kompilacji mogą wyświetlać ostrzeżenia dla użytkownika. Ten atrybut jest poprawny tylko dla właściwości oznaczonych atrybutem [Parameter]. Atrybut EditorRequiredAttribute jest wymuszany w czasie projektowania i podczas kompilowania aplikacji. Ten atrybut nie jest wymuszany w czasie wykonywania i nie gwarantuje wartości parametru niebędącej wartością null.

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

Obsługiwane są też jednowierszowe listy atrybutów:

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

Nie używaj required modyfikatora ani init metody dostępu we właściwościach parametru składnika. Składniki są zwykle tworzone i przypisywane wartości parametrów przy użyciu odbicia, które pomija gwarancje, które init i required zostały zaprojektowane do wykonania. Zamiast tego użyj atrybutu [EditorRequired] , aby określić wymagany parametr składnika.

Nie używaj init metody dostępu we właściwościach parametrów składnika, ponieważ ustawianie wartości parametrów składnika z ParameterView.SetParameterProperties użyciem odbicia, które pomija ograniczenie inicjatora tylko do inicjowania. Użyj atrybutu [EditorRequired] , aby określić wymagany parametr składnika.

Nie używaj init metody dostępu we właściwościach parametrów składnika, ponieważ ustawianie wartości parametrów składnika z ParameterView.SetParameterProperties użyciem odbicia, które pomija ograniczenie inicjatora tylko do inicjowania.

Tuples (dokumentacja interfejsu API) są obsługiwane dla parametrów składników i typów RenderFragment. W poniższym przykładzie parametru składnika są przekazywane trzy wartości w elemencie Tuple:

RenderTupleChild.razor:

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

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

RenderTupleParent.razor:

@page "/render-tuple-parent"

<PageTitle>Render Tuple Parent</PageTitle>

<h1>Render Tuple Parent Example</h1>

<RenderTupleChild Data="data" />

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

Obsługiwane są nazwane krotki , jak pokazano w poniższym przykładzie:

NamedTupleChild.razor:

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

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

NamedTuples.razor:

@page "/named-tuples"

<PageTitle>Named Tuples</PageTitle>

<h1>Named Tuples Example</h1>

<NamedTupleChild Data="data" />

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

©2005 Universal Pictures: Serenity (Nathan Fillion)

Tuples (dokumentacja interfejsu API) są obsługiwane dla parametrów składników i typów RenderFragment. W poniższym przykładzie parametru składnika są przekazywane trzy wartości w elemencie Tuple:

RenderTupleChild.razor:

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

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

RenderTupleParent.razor:

@page "/render-tuple-parent"

<PageTitle>Render Tuple Parent</PageTitle>

<h1>Render Tuple Parent Example</h1>

<RenderTupleChild Data="data" />

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

Obsługiwane są nazwane krotki , jak pokazano w poniższym przykładzie:

NamedTupleChild.razor:

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

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

NamedTuples.razor:

@page "/named-tuples"

<PageTitle>Named Tuples</PageTitle>

<h1>Named Tuples Example</h1>

<NamedTupleChild Data="data" />

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

©2005 Universal Pictures: Serenity (Nathan Fillion)

Tuples (dokumentacja interfejsu API) są obsługiwane dla parametrów składników i typów RenderFragment. W poniższym przykładzie parametru składnika są przekazywane trzy wartości w elemencie Tuple:

RenderTupleChild.razor:

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

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

RenderTupleParent.razor:

@page "/render-tuple-parent"

<h1>Render Tuple Parent</h1>

<RenderTupleChild Data="data" />

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

Obsługiwane są nazwane krotki , jak pokazano w poniższym przykładzie:

RenderNamedTupleChild.razor:

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

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

RenderNamedTupleParent.razor:

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

<h1>Render Named Tuple Parent</h1>

<RenderNamedTupleChild Data="data" />

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

©2005 Universal Pictures: Serenity (Nathan Fillion)

Parametry tras

Składniki mogą określać parametry trasy w szablonie trasy w dyrektywie @page. Router platformy Blazor używa parametrów trasy w celu wypełniania odpowiednich parametrów składnika.

RouteParameter1.razor:

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

<PageTitle>Route Parameter 1</PageTitle>

<h1>Route Parameter Example 1</h1>

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

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

<PageTitle>Route Parameter 1</PageTitle>

<h1>Route Parameter Example 1</h1>

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

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

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

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

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

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

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

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

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

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

Aby uzyskać więcej informacji, zobacz sekcję Parametry trasy ASP.NET Core Blazor routingu i nawigacji. Opcjonalne parametry trasy są również obsługiwane i omówione w tej samej sekcji. Aby uzyskać informacje na temat parametrów trasy typu catch-all ({*pageRoute}), które przechwytują ścieżki w wielu granicach folderów, zobacz sekcję Catch-all route parameters (Parametry trasy catch-all) ASP.NET Core Blazor routingu i nawigacji.

Aby uzyskać więcej informacji, zobacz sekcję Parametry trasy ASP.NET Core Blazor routingu i nawigacji. Opcjonalne parametry trasy nie są obsługiwane, dlatego wymagane są dwie @page dyrektywy (zobacz sekcję Parametry trasy, aby uzyskać więcej informacji). Aby uzyskać informacje na temat parametrów trasy typu catch-all ({*pageRoute}), które przechwytują ścieżki w wielu granicach folderów, zobacz sekcję Catch-all route parameters (Parametry trasy catch-all) ASP.NET Core Blazor routingu i nawigacji.

Ostrzeżenie

Dzięki kompresji, która jest domyślnie włączona, unikaj tworzenia bezpiecznych (uwierzytelnionych/autoryzowanych) interaktywnych składników po stronie serwera, które renderuje dane z niezaufanych źródeł. Niezaufane źródła obejmują parametry trasy, ciągi zapytań, dane z JS międzyoperacyjności i inne źródło danych, które użytkownik innej firmy może kontrolować (bazy danych, usługi zewnętrzne). Aby uzyskać więcej informacji, zobacz ASP.NET Core guidance and Threat mitigation guidance for ASP.NET Core interactive server-side rendering (Wskazówki ASP.NET CoreSignalR Blazordotyczące ograniczania zagrożeń dotyczące interaktywnego renderowania po stronie serwera ASP.NET CoreBlazor).

Fragmenty renderowania zawartości podrzędnej

Składniki mogą ustawiać zawartość innych składników. Składnik przypisujący podaje zawartość między tagiem otwierającym i tagiem zamykającym składnika podrzędnego.

W poniższym przykładzie składnik RenderFragmentChild ma parametr składnika ChildContent, który reprezentuje segment interfejsu użytkownika do renderowania jako element RenderFragment. Położenie elementu ChildContent w znacznikach aparatu Razor składnika określa miejsce, w którym jest renderowana zawartość w końcowym kodzie wyjściowym HTML.

RenderFragmentChild.razor:

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

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

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

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

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

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

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

Ważne

Właściwość otrzymująca zawartość RenderFragment musi według konwencji mieć nazwę ChildContent.

Wywołania zwrotne zdarzeń nie są obsługiwane dla elementu RenderFragment.

Poniższy składnik udostępnia zawartość renderowania RenderFragmentChild elementu przez umieszczenie zawartości wewnątrz tagów otwierania i zamykania składnika podrzędnego.

RenderFragments.razor:

@page "/render-fragments"

<PageTitle>Render Fragments</PageTitle>

<h1>Render Fragments Example</h1>

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

RenderFragments.razor:

@page "/render-fragments"

<PageTitle>Render Fragments</PageTitle>

<h1>Render Fragments Example</h1>

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

RenderFragmentParent.razor:

@page "/render-fragment-parent"

<h1>Render child content</h1>

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

RenderFragmentParent.razor:

@page "/render-fragment-parent"

<h1>Render child content</h1>

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

RenderFragmentParent.razor:

@page "/render-fragment-parent"

<h1>Render child content</h1>

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

RenderFragmentParent.razor:

@page "/render-fragment-parent"

<h1>Render child content</h1>

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

Fragmenty renderowania są używane do renderowania zawartości podrzędnej w aplikacjach platformy Blazor i zostały opisane wraz z przykładami w następujących artykułach i sekcjach artykułów:

Uwaga

Na platformie Blazor wbudowane składniki aparatu Razor używają tej samej konwencji parametrów składników ChildContent do ustawiania ich zawartości. Aby zobaczyć składniki, które ustawiają zawartość podrzędną, możesz wyszukać nazwę właściwości parametru składnika ChildContent w dokumentacji interfejsu API (filtrowanie interfejsu API przy użyciu terminu wyszukiwania „ChildContent”).

Fragmenty renderowania dla logiki renderowania do wielokrotnego użytku

Składniki podrzędne można wyodrębnić w celu ponownego używania logiki renderowania. W bloku @code dowolnego składnika zdefiniuj element RenderFragment i renderuj fragment z dowolnego miejsca tyle razy, ile jest to potrzebne:

@RenderWelcomeInfo

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

@RenderWelcomeInfo

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

Aby uzyskać więcej informacji, zobacz Ponowne używanie logiki renderowania.

Zmienne pętli z parametrami składników i zawartością podrzędną

Renderowanie składników wewnątrz for pętli wymaga zmiennej indeksu lokalnego, jeśli zmienna pętli przyrostowej jest używana przez parametry składnika lub RenderFragment zawartość podrzędną.

Rozważmy następujący RenderFragmentChild2 składnik, który ma zarówno parametr składnika (Id), jak i fragment renderowania do wyświetlania zawartości podrzędnej (ChildContent).

RenderFragmentChild2.razor:

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

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

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

Podczas renderowania RenderFragmentChild2 składnika w składniku nadrzędnym użyj lokalnej zmiennej indeksu (ct w poniższym przykładzie) zamiast zmiennej pętli (c) podczas przypisywania wartości parametru składnika i dostarczania zawartości składnika podrzędnego:

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

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

Alternatywnie należy użyć foreach pętli z Enumerable.Range zamiast for pętli:

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

Przechwytywanie odwołań do składników

Odwołania do składników umożliwiają odwoływanie się do wystąpień składników w celu wydawania poleceń. Aby przechwycić odwołanie do składnika:

  • Dodaj atrybut @ref do składnika podrzędnego.
  • Zdefiniuj pole o tym samym typie co składnik podrzędny.

Gdy składnik jest renderowany, pole jest wypełniane wystąpieniem składnika. Następnie można wywoływać metody platformy .NET w tym wystąpieniu.

Rozważmy następujący składnik ReferenceChild, który rejestruje komunikat, gdy jest wywoływana jego metoda ChildMethod.

ReferenceChild.razor:

@inject ILogger<ReferenceChild> Logger

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

@code {
    private int value;

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

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

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

@code {
    private int value;

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

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

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

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

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

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

Odwołanie do składnika zostanie wypełnione dopiero wtedy, gdy nastąpi renderowanie składnika, a jego dane wyjściowe będą zawierać element składnika ReferenceChild. Do czasu renderowania składnika nie ma do czego się odwoływać. Nie należy próbować wywołać metody składnika, do której odwołuje się program obsługi zdarzeń (na przykład @onclick="childComponent!.ChildMethod(5)"), ponieważ zmienna referencyjna może nie być przypisana w momencie przypisania zdarzenia kliknięcia.

Aby manipulować odwołaniami do składników po zakończeniu renderowania danego składnika, używaj metod OnAfterRender lub OnAfterRenderAsync.

W poniższym przykładzie użyto poprzedniego ReferenceChild składnika.

ReferenceParent.razor:

@page "/reference-parent"

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@code {
    private ReferenceChild childComponent1;
    private ReferenceChild childComponent2;

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

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

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

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

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

@code {
    private ReferenceChild childComponent1;
    private ReferenceChild childComponent2;

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

Przechwytywanie odwołań do składników używa podobnej składni jak przechwytywanie odwołań do elementów, ale nie jest funkcją współdziałającą z językiem JavaScript. Odwołania do składników nie są przekazywane do kodu języka JavaScript. Odwołania do składników są używane tylko w kodzie platformy .NET.

Ważne

Nie należy używać odwołań do składników w celu modyfikowania stanu składników podrzędnych. Zamiast tego należy używać normalnych deklaracyjnych parametrów składników w celu przekazania danych do składników podrzędnych. Używanie parametrów składników spowoduje, że składniki podrzędne będą automatycznie renderowane ponownie w odpowiednim czasie. Aby uzyskać więcej informacji, zobacz sekcję Parametry składników i artykuł Wiązanie danych na platformie ASP.NET Core Blazor.

Stosowanie atrybutu

Atrybuty można stosować do składników za pomocą dyrektywy @attribute. W poniższym przykładzie atrybut [Authorize] jest stosowany do klasy składnika:

@page "/"
@attribute [Authorize]

Warunkowe atrybuty elementu HTML i właściwości MODELU DOM

Blazor przyjmuje następujące ogólne zachowania:

  • W przypadku atrybutów Blazor HTML ustawia lub usuwa atrybut warunkowo na podstawie wartości platformy .NET. Jeśli wartość platformy .NET to false lub null, atrybut nie jest ustawiony lub jest usuwany, jeśli został wcześniej ustawiony.
  • W przypadku właściwości DOM, takich jak checked lub value, Blazor ustawia właściwość DOM na podstawie wartości .NET. Jeśli wartość platformy .NET to false lub null, właściwość DOM zostanie zresetowana do wartości domyślnej.

Atrybuty Razor składni odpowiadają atrybutom HTML i tym, które odpowiadają właściwościom MODELU DOM, pozostają nieudokumentowane, ponieważ jest to szczegóły implementacji struktury, które mogą ulec zmianie bez powiadomienia.

Ostrzeżenie

Niektóre atrybuty HTML, takie jak aria-pressed, muszą mieć wartość ciągu "true" lub "false". Ponieważ wymagają one wartości ciągu, a nie wartości logicznej, należy użyć platformy .NET string , a nie bool wartości. Jest to wymaganie ustawione przez interfejsy API DOM przeglądarki.

Nieprzetworzony kod HTML

Ciągi są zwykle renderowane przy użyciu węzłów tekstowych DOM, co oznacza, że wszelkie zawarte w nich znaczniki są ignorowane i traktowane jako tekst literałów. Aby renderować nieprzetworzony kod HTML, umieść zawartość HTML wewnątrz wartości MarkupString. Wartość jest analizowana jako kod HTML lub SVG i wstawiana w modelu DOM.

Ostrzeżenie

Renderowanie nieprzetworzonego kodu HTML utworzonego z jakiegokolwiek niezaufanego źródła jest zagrożeniem dla bezpieczeństwa i zawsze należy tego unikać.

W poniższym przykładzie pokazano użycie typu MarkupString w celu dodania bloku statycznej zawartości HTML do renderowanych danych wyjściowych składnika.

MarkupStrings.razor:

@page "/markup-strings"

<PageTitle>Markup Strings</PageTitle>

<h1>Markup Strings Example</h1>

@((MarkupString)myMarkup)

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

MarkupStrings.razor:

@page "/markup-strings"

<PageTitle>Markup Strings</PageTitle>

<h1>Markup Strings Example</h1>

@((MarkupString)myMarkup)

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

MarkupStringExample.razor:

@page "/markup-string-example"

@((MarkupString)myMarkup)

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

MarkupStringExample.razor:

@page "/markup-string-example"

@((MarkupString)myMarkup)

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

MarkupStringExample.razor:

@page "/markup-string-example"

@((MarkupString)myMarkup)

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

MarkupStringExample.razor:

@page "/markup-string-example"

@((MarkupString)myMarkup)

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

Szablony aparatu Razor

Fragmenty renderowania można definiować, używając składni szablonów aparatu Razor w celu definiowania fragmentu kodu interfejsu użytkownika. Szablony aparatu Razor używają następującego formatu:

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

Poniższy przykład przedstawia sposób określania wartości RenderFragment i RenderFragment<TValue> oraz renderowania szablonów bezpośrednio w składniku. Fragmenty renderowania można też przekazywać jako argumenty do składników z szablonami.

RazorTemplate.razor:

@page "/razor-template"

<PageTitle>Razor Template</PageTitle>

<h1>Razor Template Example</h1>

@timeTemplate

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

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

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

<PageTitle>Razor Template</PageTitle>

<h1>Razor Template Example</h1>

@timeTemplate

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

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

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

@timeTemplate

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

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

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

@timeTemplate

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

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

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

@timeTemplate

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

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

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

@timeTemplate

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

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

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

Renderowane dane wyjściowe powyższego kodu:

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

Zasoby statyczne

Platforma Blazor stosuje konwencję platformy ASP.NET Core dla zasobów statycznych. Zasoby statyczne znajdują się w folderze web root (wwwroot) projektu lub w folderach wewnątrz folderu wwwroot.

Używaj ścieżki określonej względem ścieżki bazowej (/), aby odwoływać się do katalogu głównego sieci Web w przypadku zasobu statycznego. W poniższym przykładzie plik logo.png znajduje się fizycznie w folderze {PROJECT ROOT}/wwwroot/images. {PROJECT ROOT} to katalog główny projektu aplikacji.

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

Składniki nie obsługują notacji z tyldą i ukośnikiem (~/).

Aby uzyskać informacje o ustawianiu ścieżki bazowej aplikacji, zobacz Hostowanie i wdrażanie platformy ASP.NET Core Blazor.

Pomocnicy tagów nie są obsługiwani w składnikach

Tag Helpers nie są obsługiwani w składnikach. Aby zapewnić funkcjonalność podobną do pomocników tagów na platformie Blazor, utwórz składnik o takiej samej funkcjonalności jak pomocnik tagów i użyj zamiast niego tego składnika.

Obrazy w formacie skalowalnej grafiki wektorowej (SVG)

Platforma Blazor renderuje kod HTML, więc obrazy obsługiwane przez przeglądarkę, w tym obrazy Scalable Vector Graphics (SVG) (.svg), są obsługiwane przy użyciu tagu <img>:

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

Podobnie, obrazy SVG są obsługiwane w regułach CSS pliku arkusza stylów (.css):

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

Platforma Blazor obsługuje element <foreignObject> na potrzeby wyświetlania dowolnego kodu HTML wewnątrz obrazu SVG. Ten znacznik może reprezentować dowolny kod HTML, element RenderFragment lub składnik aparatu Razor.

Poniższy przykład przedstawia:

  • Wyświetlanie elementu string (@message).
  • Wiązanie dwukierunkowe z elementem <input> i polem value.
  • Składnik Robot.
<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">
    <rect x="0" y="0" rx="10" ry="10" width="200" height="200" stroke="black" 
        fill="none" />
    <foreignObject x="20" y="20" width="160" height="160">
        <p>@message</p>
    </foreignObject>
</svg>

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

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

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

    private string? value;
}

Renderowanie odstępów

@preservewhitespace Jeśli dyrektywa nie zostanie użyta z wartością true, dodatkowe odstępy zostaną usunięte, jeśli:

  • Występują na początku lub na końcu elementu.
  • Występują na początku lub na końcu wewnątrz parametru RenderFragment/RenderFragment<TValue> (np. zawartość podrzędna przekazywana do innego składnika).
  • Poprzedzają blok kodu języka C# lub następują po takim bloku, na przykład @if lub @foreach.

Usuwanie odstępów może wpływać na renderowane dane wyjściowe w przypadku używania reguły CSS, takiej jak white-space: pre. Aby wyłączyć tę optymalizację wydajności i zachować odstępy, wykonaj jedną z następujących czynności:

  • Dodaj dyrektywę @preservewhitespace true na początku pliku Razor (.razor), aby zastosować preferencję do konkretnego składnika.
  • Dodaj dyrektywę @preservewhitespace true wewnątrz pliku _Imports.razor, aby zastosować preferencję do podkatalogu lub całego projektu.

W większości przypadków nie są wymagane żadne czynności, ponieważ aplikacje zazwyczaj nadal działają normalnie (ale szybciej). Jeśli usuwanie odstępów powoduje problem z renderowaniem konkretnego składnika, użyj w nim dyrektywy @preservewhitespace true, aby wyłączyć tę optymalizację.

Odstępy są zachowywane w znacznikach źródłowych składnika. Tekst zawierający tylko odstępy jest renderowany w modelu DOM przeglądarki nawet wtedy, gdy nie ma żadnego efektu wizualnego.

Rozważmy następujące znaczniki składnika:

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

W powyższym przykładzie renderowane są następujące niepotrzebne odstępy:

  • Poza blokiem kodu @foreach.
  • Wokół elementu <li>.
  • Wokół danych wyjściowych @item.Text.

Lista 100 elementów powoduje utworzenie ponad 400 obszarów odstępów. Żadne z dodatkowych odstępów nie wpływają wizualnie na renderowane dane wyjściowe.

Podczas renderowania statycznego kodu HTML dla składników odstępy wewnątrz tagów nie są zachowywane. Możesz na przykład wyświetlić renderowane dane wyjściowe następującego tagu <img> w pliku aparatu Razor składnika (.razor):

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

Odstępy nie są zachowywane w powyższych znacznikach:

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

Składnik główny

Składnik główny (składnik głównyRazor) jest pierwszym składnikiem załadowanym do dowolnej hierarchii składników utworzonej przez aplikację.

W aplikacji utworzonej Blazor Web App na podstawie szablonu App projektu składnik (App.razor) jest określony jako domyślny składnik główny przez parametr typu zadeklarowany dla wywołania MapRazorComponents<TRootComponent> w pliku po stronie Program serwera. W poniższym przykładzie pokazano użycie App składnika jako składnika głównego, który jest domyślnym ustawieniem aplikacji utworzonej na podstawie szablonu Blazor projektu:

app.MapRazorComponents<App>();

Uwaga

Tworzenie składnika głównego interakcyjnego, takiego jak App składnik, nie jest obsługiwane.

W aplikacji utworzonej Blazor Server na podstawie szablonu App projektu składnik (App.razor) jest określony jako domyślny składnik główny przy Pages/_Host.cshtml użyciu pomocnika tagów składników:

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

W aplikacji utworzonej Blazor WebAssembly na podstawie szablonu App projektu składnik (App.razor) jest określony jako domyślny składnik główny w Program pliku:

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

W poprzednim kodzie selektor CSS wskazuje, #appże App składnik jest określony dla elementu w wwwroot/index.html elemencie <div> o id appwartości :

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

Aplikacje MVC i Razor Pages mogą również używać pomocnika tagów składników do rejestrowania statycznie renderowanych Blazor WebAssembly składników głównych:

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

Statycznie renderowane składniki można dodawać tylko do aplikacji. Nie można ich później usunąć ani zaktualizować.

Aby uzyskać więcej informacji, zobacz następujące zasoby: