다음을 통해 공유


ASP.NET Core Razor 구성 요소

참고 항목

이 문서의 최신 버전은 아닙니다. 현재 릴리스는 이 문서의 .NET 9 버전을 참조 하세요.

Warning

이 버전의 ASP.NET Core는 더 이상 지원되지 않습니다. 자세한 내용은 .NET 및 .NET Core 지원 정책을 참조 하세요. 현재 릴리스는 이 문서의 .NET 9 버전을 참조 하세요.

Important

이 정보는 상업적으로 출시되기 전에 실질적으로 수정될 수 있는 시험판 제품과 관련이 있습니다. Microsoft는 여기에 제공된 정보에 대해 어떠한 명시적, 또는 묵시적인 보증을 하지 않습니다.

현재 릴리스는 이 문서의 .NET 9 버전을 참조 하세요.

이 문서에서는 구성 요소의 Razor 구문, 구성 요소 명명, 네임스페이스, 구성 요소 매개 변수에 대한 지침을 포함하여 Blazor 앱에서 Razor 구성 요소를 만들고 사용하는 방법을 설명합니다.

Razor 구성 요소

Blazor앱은 구성 요소, 비공식적으로Blazor 구성 요소 또는 구성 요소사용하여 빌드 Razor 됩니다. 구성 요소는 동적 동작을 사용하도록 설정하는 처리 논리가 있는 UI(사용자 인터페이스)의 자체 포함 부분입니다. 구성 요소는 중첩, 재사용, 프로젝트 간에 공유되며 MVC 및 Razor Pages 앱에서 사용할 수 있습니다.

구성 요소는 유연하고 효율적인 방법으로 UI를 업데이트하는 데 사용되는 렌더링 트리라는 브라우저 DOM(문서 개체 모델)의 메모리 내 표시로 렌더링됩니다.

"Razor 구성 요소"는 다른 ASP.NET Core 콘텐츠 렌더링 기술과 일부 이름을 공유하지만 구성 Razor 요소는 ASP.NET Core의 다음과 같은 다양한 기능과 구별되어야 합니다.

Important

사용 시 Blazor Web App대부분의 설명서 예제 구성 요소에는 상호 작용이 필요하며 문서에서 다루는 개념을 보여 Blazor 줍니다. 아티클에서 제공하는 예제 구성 요소를 테스트할 때 앱이 전역 대화형 대화형 작업을 채택하거나 구성 요소가 대화형 렌더링 모드를 채택하는지 확인합니다. 이 주제에 대한 자세한 내용은 ASP.NET Core Blazor 렌더링 모드에서 제공됩니다. 이 문서는 이 문서 뒤의 목차에 있는 다음 문서입니다.

구성 요소 클래스

구성 요소는 Razor 구성 요소 파일(.razor 파일 확장명 사용)에서 C# 및 HTML 태그 조합을 사용하여 구현됩니다.

ComponentBase 는 구성 요소 파일에서 설명하는 구성 요소의 Razor 기본 클래스입니다. ComponentBase는 구성 요소의 가장 낮은 추출인 IComponent 인터페이스를 구현합니다. ComponentBase는 기본 기능(예: 기본 제공 구성 요소 수명 주기 이벤트 집합 처리)에 대한 구성 요소 속성 및 메서드를 정의합니다.

dotnet/aspnetcore 참조 원본의 ComponentBase: 참조 원본에는 기본 제공 수명 주기 이벤트에 대한 추가 설명이 포함되어 있습니다. 그러나 구성 요소 기능의 내부 구현은 예고 없이 언제든지 변경될 수 있습니다.

참고 항목

.NET 참조 원본의 설명서 링크는 일반적으로 다음 릴리스의 .NET을 위한 현재 개발을 나타내는 리포지토리의 기본 분기를 로드합니다. 특정 릴리스를 위한 태그를 선택하려면 Switch branches or tags(분기 또는 태그 전환) 드롭다운 목록을 사용합니다. 자세한 내용은 ASP.NET Core 소스 코드(dotnet/AspNetCore.Docs #26205)의 버전 태그를 선택하는 방법을 참조하세요.

개발자는 일반적으로 Razor 구성 요소 파일(.razor)에서 Razor 구성 요소를 만들거나 ComponentBase에서 구성 요소를 기반으로 하지만 IComponent를 구현하여 구성 요소를 빌드할 수도 있습니다. IComponent를 구현 하는 개발자 빌드 구성 요소는 개발자가 만들고 유지 관리해야 하는 이벤트 및 수명 주기 메서드를 사용하여 렌더링을 수동으로 트리거하는 비용으로 렌더링을 낮은 수준으로 제어할 수 있습니다.

설명서 예제 코드 및 샘플 앱에서 채택한 Blazor 추가 규칙은 ASP.NET Core Blazor 기본 사항에서 찾을 수 있습니다.

Razor 구문

구성 요소는 Razor 구문을 사용합니다. ‘지시문’과 ‘지시문 특성’이라는 두 가지 Razor 기능이 구성 요소에서 광범위하게 사용됩니다. 이러한 기능은 Razor 태그에 표시되고 @로 시작하는 예약 키워드입니다.

  • 지시문: 구성 요소 태그가 컴파일되거나 함수되는 방식을 변경합니다. 예를 들어 지시문은 @page 특정 URL의 브라우저에서 사용자의 요청에 의해 직접 연결할 수 있는 경로 템플릿을 사용하여 라우팅 가능한 구성 요소를 지정합니다.

    규칙에 따라 구성 요소 정의(.razor 파일)의 맨 위에 있는 구성 요소의 지시문이 일관된 순서로 배치됩니다. 반복되는 지시문의 경우 지시문은 특수한 두 번째 수준 순서가 있는 지시문을 제외하고 @using 네임스페이스 또는 형식별로 사전순으로 배치됩니다.

    다음 순서는 샘플 앱 및 설명서에서 Blazor 채택됩니다. 프로젝트 템플릿에서 Blazor 제공하는 구성 요소는 다음 순서와 다를 수 있으며 다른 형식을 사용할 수 있습니다. 예를 들어 Blazor 프레임워크 Identity 구성 요소에는 지시문 블록과 지시문 블록 @using @inject 사이에 빈 줄이 포함됩니다. 사용자 고유의 앱에서 사용자 지정 주문 체계 및 형식을 자유롭게 사용할 수 있습니다.

    설명서 및 샘플 앱 Razor 지시문 순서:

    • @page
    • @rendermode (.NET 8 이상)
    • @using
      • System 네임스페이스(사전순)
      • Microsoft 네임스페이스(사전순)
      • 타사 API 네임스페이스(사전순)
      • 앱 네임스페이스(사전순)
    • 기타 지시문(사전순)

    지시문 사이에 빈 줄이 나타나지 않습니다. 지시문과 태그의 첫 번째 줄 사이에 빈 줄 Razor 하나가 나타납니다.

    예시:

    @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>
    
    ...
    
  • 지시문 특성: 구성 요소의 컴파일 방식 또는 함수를 변경합니다.

    예시:

    <input @bind="episodeId" />
    

    비 명시적 Razor 식@bind="@episodeId"()의 경우 at 기호(@)를 사용하여 지시문 특성 값을 접두사로 사용할 수 있지만 권장하지 않으며 문서에서는 예제에서 접근 방식을 채택하지 않습니다.

구성 요소에서 사용되는 지시문 및 지시문 특성은 이 문서 및 Blazor 설명서 세트의 다른 문서에서 자세히 설명합니다. Razor 구문에 대한 일반적 정보는 ASP.NET Core용 Razor 구문 참조를 참조하세요.

구성 요소 이름, 클래스 이름 및 네임스페이스

구성 요소의 이름은 대문자로 시작해야 합니다.

지원: ProductDetail.razor

지원 되지 않는: productDetail.razor

Blazor 설명서 전체에서 사용되는 일반적인 Blazor 명명 규칙은 다음과 같습니다.

  • 파일 경로 및 파일 이름은 파스칼 대/소문자를 사용하며† 코드 예제를 표시하기 전에 나타납니다. 경로가 있으면 일반적인 폴더 위치를 나타냅니다. 예를 들어 Components/Pages/ProductDetail.razor 구성 요소의 ProductDetail 파일 이름이 ProductDetail.razor 있고 앱 폴더의 폴더에 Pages Components 있음을 나타냅니다.
  • 라우팅 가능한 구성 요소의 구성 요소 파일 경로는 kebab 케이스의 URL과 일치하며 구성 요소의 경로 템플릿에 있는 단어 사이에 하이픈이 표시됩니다. 예를 들어 /product-detail(@page "/product-detail")이라는 경로 템플릿을 사용하는 ProductDetail 구성 요소는 브라우저의 상대 URL /product-detail에서 요청됩니다.

†파스칼식 대/소문자(카멜 대문자)는 공백 및 문장 부호가 없고 첫 단어를 포함하여 각 단어의 첫 글자를 대문자로 표시하는 명명 규칙입니다.
_Kebab 대/소문자 구분선은 소문자와 단어 사이에 대시를 사용하는 공백과 문장 부호가 없는 명명 규칙입니다.

구성 요소는 일반 C# 클래스이며 프로젝트 내의 어느 위치에나 배치할 수 있습니다. 웹 페이지를 생성하는 구성 요소는 일반적으로 Components/Pages 폴더에 있습니다. 페이지와 무관한 구성 요소는 Components 폴더 또는 프로젝트에 추가된 사용자 지정 폴더에 자주 배치됩니다.

일반적으로 구성 요소의 네임스페이스는 앱의 루트 네임스페이스와 앱 내의 구성 요소 위치(폴더)에서 파생됩니다. 앱의 루트 네임스페이스가 BlazorSample이고 Counter 구성 요소가 Components/Pages 폴더에 있다면 다음이 적용됩니다.

  • Counter 구성 요소의 네임스페이스는 BlazorSample.Components.Pages입니다.
  • 구성 요소의 정규화된 형식 이름은 BlazorSample.Components.Pages.Counter입니다.

구성 요소를 포함하는 사용자 지정 폴더의 경우 부모 구성 요소 또는 앱의 _Imports.razor 파일에 @using 지시문을 추가합니다. 다음 예에서는 AdminComponents 폴더의 구성 요소를 사용할 수 있도록 만듭니다.

@using BlazorSample.AdminComponents

참고 항목

@using _Imports.razor 파일의 지시문은 C# 파일(.cs)이 아닌 Razor 파일(.razor)에만 적용됩니다.

별칭이 using 지정된 문이 지원됩니다. 다음 예제에서는 앱의 다른 구성 요소에서와 같이 WeatherForecast 구성 요소의 GridRendering 공용 WeatherForecast 클래스를 사용할 수 있습니다.

@using WeatherForecast = Components.Pages.GridRendering.WeatherForecast

구성 요소는 정규화된 이름을 사용하여 참조할 수도 있습니다. 이 경우에는 @using 지시문이 필요하지 않습니다. 다음 예제에서는 앱의 AdminComponents/Pages 폴더에 있는 ProductDetail 구성 요소를 직접 참조합니다.

<BlazorSample.AdminComponents.Pages.ProductDetail />

Razor로 작성된 구성 요소의 네임스페이스는 다음을 기준으로 합니다(우선 순위에 따름).

  • Razor 파일 태그의 @namespace 지시문(예: @namespace BlazorSample.CustomNamespace).
  • 프로젝트 파일의 프로젝트 RootNamespace(예: <RootNamespace>BlazorSample</RootNamespace>).
  • 프로젝트 네임스페이스 및 프로젝트 루트에서 구성 요소로의 경로입니다. 예를 들어 프레임워크는 구성 요소의 BlazorSample 네임스페이스에 대한 Home 프로젝트 네임스페이스 BlazorSample.Components.Pages 로 확인 {PROJECT NAMESPACE}/Components/Pages/Home.razor 됩니다. {PROJECT NAMESPACE} 는 프로젝트 네임스페이스입니다. 구성 요소는 C# 이름 바인딩 규칙을 따릅니다. 이 예제의 Home 구성 요소에 대해 범위의 구성 요소는 모두 구성 요소입니다.
    • 동일한 폴더의 Components/Pages.
    • 다른 네임스페이스를 명시적으로 지정하지 않는 프로젝트 루트의 구성 요소

다음은 지원되지 않습니다.

  • global:: 한정
  • 부분적으로 정규화된 이름. 예를 들어 @using BlazorSample.Components을 구성 요소에 추가한 다음, <Layout.NavMenu></Layout.NavMenu>를 사용하여 앱의 Components/Layout 폴더(Components/Layout/NavMenu.razor)에서 NavMenu 구성 요소를 참조할 수 없습니다.

구성 요소의 이름은 대문자로 시작해야 합니다.

지원: ProductDetail.razor

지원 되지 않는: productDetail.razor

Blazor 설명서 전체에서 사용되는 일반적인 Blazor 명명 규칙은 다음과 같습니다.

  • 파일 경로 및 파일 이름은 파스칼 대/소문자를 사용하며† 코드 예제를 표시하기 전에 나타납니다. 경로가 있으면 일반적인 폴더 위치를 나타냅니다. 예를 들어 Pages/ProductDetail.razorProductDetail 구성 요소가 ProductDetail.razor라는 파일 이름을 포함하고 앱의 Pages 폴더에 있음을 나타냅니다.
  • 라우팅 가능한 구성 요소의 구성 요소 파일 경로는 kebab 케이스의 URL과 일치하며 구성 요소의 경로 템플릿에 있는 단어 사이에 하이픈이 표시됩니다. 예를 들어 /product-detail(@page "/product-detail")이라는 경로 템플릿을 사용하는 ProductDetail 구성 요소는 브라우저의 상대 URL /product-detail에서 요청됩니다.

†파스칼식 대/소문자(카멜 대문자)는 공백 및 문장 부호가 없고 첫 단어를 포함하여 각 단어의 첫 글자를 대문자로 표시하는 명명 규칙입니다.
_Kebab 대/소문자 구분선은 소문자와 단어 사이에 대시를 사용하는 공백과 문장 부호가 없는 명명 규칙입니다.

구성 요소는 일반 C# 클래스이며 프로젝트 내의 어느 위치에나 배치할 수 있습니다. 웹 페이지를 생성하는 구성 요소는 일반적으로 Pages 폴더에 있습니다. 페이지와 무관한 구성 요소는 Shared 폴더 또는 프로젝트에 추가된 사용자 지정 폴더에 자주 배치됩니다.

일반적으로 구성 요소의 네임스페이스는 앱의 루트 네임스페이스와 앱 내의 구성 요소 위치(폴더)에서 파생됩니다. 앱의 루트 네임스페이스가 BlazorSample이고 Counter 구성 요소가 Pages 폴더에 있다면 다음이 적용됩니다.

  • Counter 구성 요소의 네임스페이스는 BlazorSample.Pages입니다.
  • 구성 요소의 정규화된 형식 이름은 BlazorSample.Pages.Counter입니다.

구성 요소를 포함하는 사용자 지정 폴더의 경우 부모 구성 요소 또는 앱의 _Imports.razor 파일에 @using 지시문을 추가합니다. 다음 예에서는 AdminComponents 폴더의 구성 요소를 사용할 수 있도록 만듭니다.

@using BlazorSample.AdminComponents

참고 항목

@using _Imports.razor 파일의 지시문은 C# 파일(.cs)이 아닌 Razor 파일(.razor)에만 적용됩니다.

별칭이 using 지정된 문이 지원됩니다. 다음 예제에서는 앱의 다른 구성 요소에서와 같이 WeatherForecast 구성 요소의 GridRendering 공용 WeatherForecast 클래스를 사용할 수 있습니다.

@using WeatherForecast = Pages.GridRendering.WeatherForecast

구성 요소는 정규화된 이름을 사용하여 참조할 수도 있습니다. 이 경우에는 @using 지시문이 필요하지 않습니다. 다음 예제에서는 앱의 Components 폴더에 있는 ProductDetail 구성 요소를 직접 참조합니다.

<BlazorSample.Components.ProductDetail />

Razor로 작성된 구성 요소의 네임스페이스는 다음을 기준으로 합니다(우선 순위에 따름).

  • Razor 파일 태그의 @namespace 지시문(예: @namespace BlazorSample.CustomNamespace).
  • 프로젝트 파일의 프로젝트 RootNamespace(예: <RootNamespace>BlazorSample</RootNamespace>).
  • 프로젝트 네임스페이스 및 프로젝트 루트에서 구성 요소로의 경로입니다. 예를 들어 프레임워크는 구성 요소의 BlazorSample 네임스페이스에 대한 Index 프로젝트 네임스페이스 BlazorSample.Pages 로 확인 {PROJECT NAMESPACE}/Pages/Index.razor 됩니다. {PROJECT NAMESPACE} 는 프로젝트 네임스페이스입니다. 구성 요소는 C# 이름 바인딩 규칙을 따릅니다. 이 예제의 Index 구성 요소에 대해 범위의 구성 요소는 모두 구성 요소입니다.
    • 동일한 폴더의 Pages.
    • 다른 네임스페이스를 명시적으로 지정하지 않는 프로젝트 루트의 구성 요소

다음은 지원되지 않습니다.

  • global:: 한정
  • 부분적으로 정규화된 이름. 예를 들어 @using BlazorSample을 구성 요소에 추가한 다음, <Shared.NavMenu></Shared.NavMenu>를 사용하여 앱의 Shared 폴더(Shared/NavMenu.razor)에서 NavMenu 구성 요소를 참조할 수 없습니다.

Partial 클래스 지원

구성 요소는 C# partial 클래스로 생성되며 다음 방법 중 하나를 사용하여 작성됩니다.

  • 단일 파일에 하나 이상의 @code 블록, HTML 태그, Razor 태그에 정의된 C# 코드를 포함합니다. Blazor 프로젝트 템플릿은 이 단일 파일 방법을 사용하여 해당 구성 요소를 정의합니다.
  • HTML 및 Razor 태그를 Razor 파일(.razor)에 배치합니다. C# 코드는 partial 클래스로 정의된 코드 숨김 파일(.cs)에 배치됩니다.

참고 항목

구성 요소별 스타일을 정의하는 구성 요소 스타일시트는 별도의 파일(.css)입니다. Blazor CSS 격리는 ASP.NET Core Blazor CSS 격리에서 설명합니다.

다음 예제에서는 Blazor 프로젝트 템플릿에서 생성된 앱의 @code 블록을 포함하는 기본 Counter 구성 요소를 보여 줍니다. 태그 및 C# 코드는 동일한 파일에 있습니다. 이 방법은 구성 요소 제작에서 가장 일반적으로 사용됩니다.

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

다음 Counter 구성 요소는 부분 클래스가 있는 코드 숨김 파일을 사용하여 C# 코드에서 프레젠테이션 HTML 및 Razor 태그를 분할합니다. C# 코드에서 태그를 분할하는 것은 일부 조직과 개발자가 원하는 작업 방식에 맞게 구성 요소 코드를 구성하는 데 선호됩니다. 예를 들어 조직의 UI 전문가는 구성 요소의 C# 논리에서 작업하는 다른 개발자와 독립적으로 프레젠테이션 계층에서 작업할 수 있습니다. 이 방법은 자동으로 생성된 코드 또는 소스 생성기를 사용하는 경우에도 유용합니다. 자세한 내용은 부분 클래스 및 메서드(C# 프로그래밍 가이드)를 참조하세요.

CounterPartialClass.razor:

@page "/counter-partial-class"

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

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

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

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

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

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

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

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

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

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

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

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

<h1>Counter</h1>

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

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

<h1>Counter</h1>

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

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

CounterPartialClass.razor.cs:

namespace BlazorSample.Components.Pages;

public partial class CounterPartialClass
{
    private int currentCount = 0;

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

public partial class CounterPartialClass
{
    private int currentCount = 0;

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

public partial class CounterPartialClass
{
    private int currentCount = 0;

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

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

@using _Imports.razor 파일의 지시문은 C# 파일(.cs)이 아닌 Razor 파일(.razor)에만 적용됩니다. 필요에 따라 partial 클래스 파일에 네임스페이스를 추가합니다.

구성 요소에서 사용되는 일반적인 네임스페이스는 다음과 같습니다.

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;

일반적인 네임스페이스에는 앱의 네임스페이스와 앱의 Components 폴더에 해당하는 네임스페이스도 포함됩니다.

using BlazorSample;
using BlazorSample.Components;

폴더와 같은 Layout 추가 폴더도 포함할 수 있습니다.

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

일반적인 네임스페이스에는 앱의 네임스페이스와 앱의 Shared 폴더에 해당하는 네임스페이스도 포함됩니다.

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;

일반적인 네임스페이스에는 앱의 네임스페이스와 앱의 Shared 폴더에 해당하는 네임스페이스도 포함됩니다.

using BlazorSample;
using BlazorSample.Shared;

기본 클래스 지정

@inherits 지시문을 사용하여 구성 요소의 기본 클래스를 지정합니다. C# 논리에서만 태그를 분할하는 부분 클래스를 사용하는 것과 달리 기본 클래스를 사용하면 기본 클래스의 속성과 메서드를 공유하는 구성 요소 그룹에서 사용할 C# 코드를 상속할 수 있습니다. 기본 클래스를 사용하면 앱의 코드 중복성이 감소하며 클래스 라이브러리에서 여러 앱으로 기본 코드를 제공할 때 유용합니다. 자세한 내용은 C# 및 .NET의 상속을 참조하세요.

다음 예제에서 기본 클래스는 BlazorRocksBase1 .에서 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!";
}

라우팅

Blazor의 라우팅은 @page 지시문으로 앱의 액세스 가능한 각 구성 요소에 경로 템플릿을 제공하여 수행됩니다. @page 지시문을 포함하는 Razor 파일이 컴파일되면 생성된 클래스에 경로 템플릿을 지정하는 RouteAttribute가 제공됩니다. 런타임에 라우터는 RouteAttribute를 사용하여 구성 요소 클래스를 검색하고 요청한 URL과 일치하는 경로 템플릿이 있는 모든 구성 요소를 렌더링합니다.

다음 HelloWorld 구성 요소는 /hello-world의 경로 템플릿을 사용하며 구성 요소에 대해 렌더링된 웹 페이지는 상대 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>

위의 구성 요소는 앱의 UI 탐색에 구성 요소를 추가하는지와 관계없이 브라우저의 /hello-world에서 로드됩니다. 필요에 따라 구성 요소를 NavMenu 구성 요소에 추가하여 구성 요소에 대한 링크가 앱의 UI 기반 탐색에 나타나도록 할 수 있습니다.

이전 HelloWorld 구성 요소의 경우 구성 요소에 NavLink 구성 요소를 NavMenu 추가할 수 있습니다. NavLinkNavMenu 구성 요소의 설명을 포함한 자세한 내용은 ASP.NET Core Blazor 라우팅 및 탐색을 참조하세요.

가격 인상

구성 요소의 UI는 Razor 태그인 C# 및 HTML로 구성되는 Razor 구문을 사용하여 정의됩니다. 앱이 컴파일되면 HTML 태그 및 C# 렌더링 논리는 구성 요소 클래스로 변환됩니다. 생성된 클래스의 이름은 파일 이름과 일치합니다.

구성 요소 클래스의 멤버는 하나 이상의 @code 블록에 정의됩니다. @code 블록에서 구성 요소 상태는 C#으로 지정되고 처리됩니다.

  • 속성 및 필드 이니셜라이저.
  • 부모 구성 요소에서 전달한 인수 및 경로 매개 변수의 매개 변수 값.
  • 사용자 이벤트 처리, 수명 주기 이벤트, 사용자 지정 구성 요소 논리에 대한 메서드.

구성 요소 멤버는 @ 기호로 시작하는 C# 식을 사용하는 렌더링 논리에서 사용됩니다. 예를 들어, C# 필드는 필드 이름에 앞에 @을 붙여 렌더링됩니다. 다음 Markup 구성 요소는 다음을 평가하고 렌더링합니다.

  • 제목 요소의 CSS 속성 값 font-style에 대한 headingFontStyle.
  • 제목 요소의 콘텐츠에 대한 headingText.

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

참고 항목

Blazor 설명서 전체의 예제에서 프라이빗 멤버에 대해 private 액세스 한정자를 지정합니다. 프라이빗 멤버는 구성 요소의 클래스로 범위가 지정됩니다. 그러나 C#에서는 액세스 한정자가 없는 경우 private 액세스 한정자를 가정하므로 직접 작성한 코드에서 멤버를 “private”으로 명시적으로 표시하는 것은 선택 사항입니다. 액세스 한정자에 대한 자세한 내용은 액세스 한정자(C# 프로그래밍 가이드)를 참조하세요.

프레임워크는 Blazor 구성 요소를 내부적으로 렌더링 트리처리합니다. 이 트리는 구성 요소의 DOM과 CSSOM(Cascading Style Sheet Object Model)의 조합입니다. 구성 요소가 처음에 렌더링되면 이벤트에 대한 응답으로 구성 요소의 렌더링 트리가 다시 생성됩니다. Blazor는 이전 렌더링 트리에 대해 새 렌더링 트리를 비교하고 수정 사항을 브라우저의 DOM에 적용하여 표시합니다. 자세한 내용은 ASP.NET Core Razor 구성 요소 렌더링을 참조하세요.

C# 제어 구조, 지시문, 지시문 특성에 대한 Razor 구문은 소문자입니다(예: @if, @code, @bind). 속성 이름은 대문자입니다(예: LayoutComponentBase.Body의 경우 @Body).

비동기 메서드(async)는 void 반환을 지원하지 않습니다.

Blazor 프레임워크는 void 반환 비동기 메서드(async)를 추적하지 않습니다. 따라서 void가 반환되는 경우 예외가 발견되지 않습니다. 항상 비동기 메서드에서 Task를 반환합니다.

중첩된 구성 요소

구성 요소는 HTML 구문을 사용하여 선언함으로써 다른 구성 요소를 포함할 수 있습니다. 구성 요소 사용을 위한 태그는 태그 이름이 구성 요소 유형인 HTML 태그처럼 보입니다.

다른 구성 요소에서 제목을 표시하는 데 사용할 수 있는 다음 Heading 구성 요소를 살펴보세요.

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

HeadingExample 구성 요소의 다음 태그는 <Heading /> 태그가 나타나는 위치에서 위의 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 />

구성 요소에 동일한 네임스페이스 내에 있는 구성 요소 이름과 일치하지 않는 HTML 요소(첫 글자가 대문자임)가 포함되면 요소에 예기치 않은 이름이 있음을 나타내는 경고가 발생합니다. 구성 요소 네임스페이스에 대한 @using 지시문을 추가하면 해당 구성 요소를 사용할 수 있게 되므로 경고가 해결됩니다. 자세한 내용은 구성 요소 이름, 클래스 이름 및 네임스페이스 섹션을 참조하세요.

이 섹션에 표시된 Heading 구성 요소 예제에는 @page 지시문이 없으므로 사용자가 브라우저에서 직접 요청하여 Heading 구성 요소에 직접 액세스할 수 없습니다. 그러나 @page 지시문이 있는 구성 요소는 다른 구성 요소에 중첩될 수 있습니다. Razor 파일 맨 위에 @page "/heading"을 포함하여 Heading 구성 요소에 직접 액세스할 수 있는 경우 구성 요소는 /heading/heading-example에서 브라우저 요청에 대해 렌더링됩니다.

구성 요소 매개 변수

‘구성 요소 매개 변수’는 구성 요소에 데이터를 전달하고 [Parameter] 특성이 있는 구성 요소 클래스에서 퍼블릭 C# 속성을 사용하여 정의됩니다. 다음 예제에서는 기본 제공 참조 형식(System.String) 및 사용자 정의 참조 형식(PanelBody)이 구성 요소 매개 변수로 전달됩니다.

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

Warning

구성 요소 매개 변수에 초기 값을 제공할 수는 있지만 구성 요소가 처음으로 렌더링된 후 고유한 매개 변수에 쓰는 구성 요소는 만들지 마세요. 자세한 내용은 ASP.NET Core에서 매개 변수 덮어쓰기 방지를 참조 하세요 Blazor.

ParameterChild 구성 요소의 TitleBody 구성 요소 매개 변수는 구성 요소의 인스턴스를 렌더링하는 HTML 태그의 인수에서 설정됩니다. 다음 ParameterParent 구성 요소는 두 개의 ParameterChild 구성 요소를 렌더링합니다.

  • 첫 번째 ParameterChild 구성 요소는 매개 변수 인수를 제공하지 않고 렌더링됩니다.
  • 두 번째 ParameterChild 구성 요소는 ParameterParent 구성 요소에서 TitleBody 값을 받고, 명시적 C# 식을 사용하여 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" })" />

ParameterParent 구성 요소에서 렌더링된 다음 HTML 태그는 ParameterParent 구성 요소가 구성 요소 매개 변수 값을 제공하지 않는 경우 ParameterChild 구성 요소 기본값을 보여 줍니다. ParameterParent 구성 요소가 구성 요소 매개 변수 값을 제공하는 경우 ParameterChild 구성 요소의 기본값을 바꿉니다.

참고 항목

명확하게 하기 위해 렌더링된 CSS 스타일 클래스는 다음과 같은 렌더링된 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>

구성 요소 매개 변수에 메서드의 C# 필드, 속성 또는 결과를 HTML 특성 값으로 할당합니다. 특성 값은 일반적으로 매개 변수 형식과 일치하는 모든 C# 식일 수 있습니다. 특성 값은 필요에 따라 예약 기호@Razor 이어질 수 있지만 필수는 아닙니다.

구성 요소 매개 변수가 문자열 형식인 경우 특성 값은 대신 C# 문자열 리터럴로 처리됩니다. 대신 C# 식을 지정하려면 접두사를 @ 사용합니다.

다음 ParameterParent2 구성 요소는 위 ParameterChild 구성 요소의 인스턴스 4개를 표시하고 해당 Title 매개 변수 값을 다음으로 설정합니다.

  • title 필드의 값
  • GetTitle C# 메서드의 결과
  • ToLongDateString을 사용하는 긴 형식의 현재 로컬 날짜로, 암시적 C# 식 사용
  • panelData 개체의 Title 속성

매개 변수 특성 값에 대한 따옴표는 HTML5 사양에 따라 대부분의 경우 선택 사항입니다. 예를 들어 Value=thisValue="this" 대신 지원됩니다. 하지만 웹 기반 기술에서 기억하기 쉽고 널리 채택되기 때문에 따옴표를 사용하는 것이 좋습니다.

문서 전체에서 코드 예제는 다음과 같습니다.

  • 항상 따옴표를 사용합니다. 예: Value="this"
  • 필수가 아니면 접두사를 비리터럴과 함께 사용하지 @ 마세요. 예: Count="ct"숫자 형식 변수는 어디에 ct 있습니다. Count="@ct" 은 유효한 스타일 방식이지만 설명서와 예제는 규칙을 채택하지 않습니다.
  • 식 외부에서 Razor 는 항상 리터럴을 사용하지 @ 않습니다. 예: IsFixed="true" 여기에는 키워드(예: this) 및 null키워드가 포함되지만 원하는 경우 키워드를 사용하도록 선택할 수 있습니다. 예를 들어 IsFixed="@true"는 일반적이지는 않지만 지원됩니다.

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

참고 항목

C# 멤버를 구성 요소 매개 변수에 할당할 때 매개 변수의 HTML 특성 @앞에 접두사를 지정하지 마세요.

정답(Title 문자열 매개 변수, Count 숫자 형식 매개 변수):

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

오답입니다:

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

Razor 페이지(.cshtml)에서와 달리 Blazor는 구성 요소를 렌더링하는 동안 Razor 식에서 비동기 작업을 수행할 수 없습니다. 이는 Blazor가 대화형 Ui를 렌더링하는 용도로 설계되었기 때문입니다. 대화형 UI에서 화면은 항상 무언가를 표시해야 하므로 렌더링 흐름을 차단하는 것은 적합하지 않습니다. 대신 비동기 작업은 비동기 수명 주기 이벤트 중 하나에서 수행됩니다. 각 비동기 수명 주기 이벤트 이후 구성 요소가 다시 렌더링될 수 있습니다. 다음 Razor 구문은 지원되지 않습니다.

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

위 예제의 코드는 앱이 빌드될 때 ‘컴파일러 오류’를 생성합니다.

'Await' 연산자는 비동기 메서드 내에서만 사용할 수 있습니다. 이 메서드를 'Async' 한정자로 표시하고 해당 반환 형식을 'Task'로 변경하세요.

위 예제의 Title 매개 변수에 대한 값을 비동기식으로 가져오려면 다음 예제와 같이 구성 요소에서 OnInitializedAsync 수명 주기 이벤트를 사용하면 됩니다.

<ParameterChild Title="@title" />

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

자세한 내용은 ASP.NET Core Razor 구성 요소 수명 주기를 참조하세요.

매개 변수에 할당하기 위해 텍스트와 식 결과를 연결하는 데 명시적 Razor 식을 사용할 수 없습니다. 다음 예제에서는 “Set by ” 텍스트를 개체의 속성 값과 연결합니다. 이 구문은 Razor 페이지(.cshtml)에서 지원되지만 구성 요소 자식의 Title 매개 변수에 할당하는 데는 유효하지 않습니다. 다음 Razor 구문은 지원되지 않습니다.

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

위 예제의 코드는 앱이 빌드될 때 ‘컴파일러 오류’를 생성합니다.

구성 요소 특성은 복합 콘텐츠(C# 및 마크업 혼합)를 지원하지 않습니다.

구성된 값의 할당을 지원하려면 메서드, 필드 또는 속성을 사용합니다. 다음 예제에서는 C# 메서드 GetTitle에서 “Set by ”와 개체의 속성 값을 연결합니다.

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

자세한 내용은 ASP.NET Core용 Razor 구문 참조를 참조하세요.

Warning

구성 요소 매개 변수에 초기 값을 제공할 수는 있지만 구성 요소가 처음으로 렌더링된 후 고유한 매개 변수에 쓰는 구성 요소는 만들지 마세요. 자세한 내용은 ASP.NET Core에서 매개 변수 덮어쓰기 방지를 참조 하세요 Blazor.

구성 요소 매개 변수는 ‘auto 속성’으로 선언해야 합니다. 즉, get 또는 set 접근자에 사용자 지정 논리를 포함하지 않아야 합니다. 예를 들어 다음 StartData 속성은 auto 속성입니다.

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

구성 요소 매개 변수는 순전히 부모 구성 요소에서 자식 구성 요소로 정보를 전달하는 통로로서 사용하기 위한 것이므로 사용자 지정 논리를 get 또는 set 접근자에 배치하지 마세요. 자식 구성 요소 속성의 set 접근자에 부모 구성 요소의 렌더링을 발생시키는 논리가 포함된 경우 무한 렌더링 루프가 발생합니다.

받은 매개 변수 값을 변환하려면 다음을 수행합니다.

  • 매개 변수 속성을 auto 속성으로 유지하여 제공된 원시 데이터를 표시합니다.
  • 다른 속성이나 메서드를 만들어 매개 변수 속성을 기반으로 변환된 데이터를 제공합니다.

OnParametersSetAsync를 재정의하여 새 데이터를 받을 때마다 받은 매개 변수를 변환합니다.

초기 값 할당은 Blazor의 자동 구성 요소 렌더링에 방해가 되지 않으므로 구성 요소 매개 변수에 초기 값 쓰기가 지원됩니다. DateTime.Now를 사용하여 현재 로컬 DateTimeStartData에 할당하는 다음 구문은 구성 요소에서 유효합니다.

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

DateTime.Now의 초기 할당 후에는 개발자 코드에서 StartData에 값을 할당하지 마세요. 자세한 내용은 ASP.NET Core에서 매개 변수 덮어쓰기 방지를 참조 하세요 Blazor.

[EditorRequired] 특성을 적용하여 필수 구성 요소 매개 변수를 지정합니다. 매개 변수 값이 제공되지 않으면 편집기 또는 빌드 도구에서 사용자에게 경고를 표시할 수 있습니다. 이 특성은 [Parameter] 특성으로도 표시된 속성에서만 유효합니다. EditorRequiredAttribute는 디자인 타임과 앱이 빌드될 때 적용됩니다. 이 특성은 런타임에 적용되지 않으며 null이 아닌 매개 변수 값을 보장하지 않습니다.

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

단일 줄 특성 목록도 지원됩니다.

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

구성 요소 매개 변수 속성에는 required 한정자 또는 init 접근자를 사용하지 마세요. 구성 요소는 일반적으로 리플렉션을 사용하여 인스턴스화되고 할당된 매개 변수 값으로, 보장 init required 을 무시하고 생성하도록 설계되었습니다. 대신 특성을 사용하여 [EditorRequired] 필수 구성 요소 매개 변수를 지정합니다.

구성 요소 매개 변수 값을 ParameterView.SetParameterProperties 설정하면 init 전용 setter 제한을 우회하는 리플렉션이 사용되므로 구성 요소 매개 변수 속성에 접근자를 사용하지 init 마세요. [EditorRequired] 특성을 사용하여 필수 구성 요소 매개 변수를 지정합니다.

구성 요소 매개 변수 값을 ParameterView.SetParameterProperties 설정하면 init 전용 setter 제한을 우회하는 리플렉션이 사용되므로 구성 요소 매개 변수 속성에 접근자를 사용하지 init 마세요.

Tuples(API 설명서)는 구성 요소 매개 변수 및 RenderFragment 형식에 대해 지원됩니다. 다음 구성 요소 매개 변수 예제에서는 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);
}

다음 예제와 같이 명명된 튜플이 지원됩니다.

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

Quote ©2005 Universal Pictures: Serenity(Nathan Fillion)

Tuples(API 설명서)는 구성 요소 매개 변수 및 RenderFragment 형식에 대해 지원됩니다. 다음 구성 요소 매개 변수 예제에서는 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);
}

다음 예제와 같이 명명된 튜플이 지원됩니다.

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

Quote ©2005 Universal Pictures: Serenity(Nathan Fillion)

Tuples(API 설명서)는 구성 요소 매개 변수 및 RenderFragment 형식에 대해 지원됩니다. 다음 구성 요소 매개 변수 예제에서는 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);
}

다음 예제와 같이 명명된 튜플이 지원됩니다.

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

Quote ©2005 Universal Pictures: Serenity(Nathan Fillion)

경로 매개 변수

구성 요소는 @page 지시문의 경로 템플릿에서 경로 매개 변수를 지정할 수 있습니다. Blazor 라우터는 경로 매개 변수를 사용하여 해당 구성 요소 매개 변수를 채웁니다.

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

자세한 내용은 ASP.NET Core Blazor 라우팅 및 탐색경로 매개 변수 섹션을 참조하세요. 선택적 경로 매개 변수도 지원되며 동일한 섹션에서 다룹니다. 여러 폴더 경계를 넘어 경로를 캡처하는 catch-all 경로 매개 변수({*pageRoute})에 대한 자세한 내용은 ASP.NET Core Blazor 라우팅 및 탐색Catch-all 경로 매개 변수 섹션을 참조하세요.

자세한 내용은 ASP.NET Core Blazor 라우팅 및 탐색경로 매개 변수 섹션을 참조하세요. 선택적 경로 매개 변수는 지원되지 않으므로 두 개의 @page 지시문이 필요합니다(자세한 내용은 경로 매개 변수 섹션 참조). 여러 폴더 경계를 넘어 경로를 캡처하는 catch-all 경로 매개 변수({*pageRoute})에 대한 자세한 내용은 ASP.NET Core Blazor 라우팅 및 탐색Catch-all 경로 매개 변수 섹션을 참조하세요.

Warning

기본적으로 사용하도록 설정된 압축을 사용하면 신뢰할 수 없는 원본에서 데이터를 렌더링하는 보안(인증/권한이 부여된) 대화형 서버 쪽 구성 요소를 만들지 마세요. 신뢰할 수 없는 원본에는 경로 매개 변수, 쿼리 문자열, interop의 데이터 JS 및 타사 사용자가 제어할 수 있는 기타 데이터 원본(데이터베이스, 외부 서비스)이 포함됩니다. 자세한 내용은 ASP.NET Core BlazorSignalR 대화형 서버 쪽 렌더링에 대한 ASP.NET Core Blazor 지침위협 완화 지침을 참조하세요.

자식 콘텐츠 렌더링 조각

구성 요소는 다른 구성 요소의 콘텐츠를 설정할 수 있습니다. 할당하는 구성 요소는 자식 구성 요소의 여는 태그와 닫는 태그 사이에 콘텐츠를 제공합니다.

다음 예제에서 RenderFragmentChild 구성 요소에는 RenderFragment로 렌더링할 UI의 세그먼트를 나타내는 ChildContent 구성 요소 매개 변수가 있습니다. 구성 요소의 Razor 태그에서 ChildContent의 위치는 최종 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; }
}

Important

RenderFragment 콘텐츠를 받는 속성은 규칙에 따라 이름 ChildContent가 지정되어야 합니다.

RenderFragment에 대해 이벤트 콜백은 지원되지 않습니다.

다음 구성 요소는 자식 구성 요소의 여는 태그 및 닫는 태그 내에 콘텐츠를 배치하여 렌더링 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>

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>

렌더링 조각은 Blazor 앱 전체에서 자식 콘텐츠를 렌더링하는 데 사용되며 다음 문서 및 문서 섹션에 예제와 함께 설명되어 있습니다.

참고 항목

Blazor 프레임워크의 기본 제공 Razor 구성 요소는 동일한 ChildContent 구성 요소 매개 변수 규칙을 사용하여 콘텐츠를 설정합니다. API 설명서(검색어 "ChildContent"로 API 필터링)에서 구성 요소 매개 변수 속성 이름 ChildContent를 검색하여 자식 콘텐츠를 설정하는 구성 요소를 확인할 수 있습니다.

재사용 가능한 렌더링 논리에 대한 렌더링 조각

순전히 렌더링 논리를 다시 사용하는 방법으로 자식 구성 요소를 분리할 수 있습니다. 모든 구성 요소의 @code 블록에서 필요에 따라 임의의 위치에서 RenderFragment를 정의하고 조각을 정의하고 렌더링합니다.

@RenderWelcomeInfo

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

@RenderWelcomeInfo

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

자세한 내용은 렌더링 논리 재사용을 참조하세요.

구성 요소 매개 변수 및 자식 콘텐츠를 사용하여 변수 반복

구성 요소의 매개 변수 또는 RenderFragment 자식 콘텐츠에서 증분 루프 변수를 사용하는 경우 루프 내에서 for 구성 요소를 렌더링하려면 로컬 인덱스 변수가 필요합니다.

자식 콘텐츠(ChildContent)를 표시할 구성 요소 매개 변수(Id) 및 렌더링 조각이 모두 있는 다음 RenderFragmentChild2 구성 요소를 고려합니다.

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

부모 구성 요소에서 구성 요소를 렌더링할 RenderFragmentChild2 때 구성 요소 매개 변수ct 값을 할당하고 자식 구성 요소의 콘텐츠를 제공할 때 루프 변수 대신 로컬 인덱스 변수(c다음 예제)를 사용합니다.

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

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

또는 루프 대신 루프 Enumerable.Range 를 사용합니다foreach.for

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

구성 요소에 대한 참조 캡처

구성 요소 참조는 명령을 실행하기 위해 구성 요소 인스턴스를 참조하는 방법을 제공합니다. 구성 요소 참조를 캡처하려면 다음을 수행합니다.

  • 자식 구성 요소에 @ref 특성을 추가합니다.
  • 자식 구성 요소와 동일한 유형으로 필드를 정의합니다.

구성 요소가 렌더링되면 필드가 구성 요소 인스턴스로 채워집니다. 그러면 인스턴스에서 .NET 메서드를 호출할 수 있습니다.

해당 ChildMethod가 호출될 때 메시지를 기록하는 다음 ReferenceChild 구성 요소를 살펴보세요.

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

구성 요소 참조는 구성 요소가 렌더링된 후에만 채워지고 출력에는 ReferenceChild의 요소가 포함됩니다. 구성 요소가 렌더링될 때까지는 참조할 요소가 없습니다. 참조된 구성 요소 메서드를 이벤트 처리기에 직접 호출하지 마세요(예 @onclick="childComponent!.ChildMethod(5)": 클릭 이벤트가 할당될 때 참조 변수가 할당되지 않을 수 있음).

구성 요소가 렌더링을 완료한 후 구성 요소 참조를 조작하려면 OnAfterRender 또는 OnAfterRenderAsync 메서드를 사용합니다.

다음 예제에서는 이전 ReferenceChild 구성 요소를 사용합니다.

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

구성 요소 참조 캡처에서 요소 참조 캡처와 유사한 구문을 사용하지만 구성 요소 참조 캡처는 JavaScript interop 기능이 아닙니다. 구성 요소 참조가 JavaScript 코드로 전달되지 않습니다. 구성 요소 참조는 .NET 코드에서만 사용됩니다.

Important

구성 요소 참조를 사용하여 자식 구성 요소의 상태를 변경하지 않도록 합니다. 대신 일반 선언적 구성 요소 매개 변수를 사용하여 자식 구성 요소에 데이터를 전달합니다. 구성 요소 매개 변수를 사용하면 자식 구성 요소가 올바른 시간에 자동으로 다시 렌더링됩니다. 자세한 내용은 구성 요소 매개 변수 섹션 및 ASP.NET Core Blazor 데이터 바인딩 문서를 참조하세요.

특성 적용

특성은 @attribute 지시문을 사용하여 구성 요소에 적용할 수 있습니다. 다음 예제에서는 [Authorize] 특성을 구성 요소의 클래스에 적용합니다.

@page "/"
@attribute [Authorize]

조건부 HTML 요소 특성 및 DOM 속성

Blazor 는 다음과 같은 일반적인 동작을 채택합니다.

  • HTML 특성 Blazor 의 경우 .NET 값에 따라 조건부로 특성을 설정하거나 제거합니다. .NET 값이 false 거나 null, 특성이 설정되지 않았거나 이전에 설정된 경우 제거됩니다.
  • DOM 속성(예: checked 또는 value) Blazor 의 경우 .NET 값을 기반으로 DOM 속성을 설정합니다. .NET 값이 false 거나 nullDOM 속성이 기본값으로 다시 설정됩니다.

Razor HTML 특성에 해당하는 구문 특성과 DOM 속성에 해당하는 구문 특성은 예고 없이 변경될 수 있는 프레임워크 구현 세부 정보이므로 문서화되지 않은 상태로 유지됩니다.

Warning

일부 HTML 특성(예: aria-pressed"true" 또는 "false")의 문자열 값이 있어야 합니다. 부울이 아닌 문자열 값이 필요하므로 해당 값에 대한 값이 아닌 .NET stringbool 사용해야 합니다. 브라우저 DOM API에서 설정한 요구 사항입니다.

원시 HTML

일반적으로 문자열은 DOM 텍스트 노드를 사용하여 렌더링됩니다. 즉, 포함될 수 있는 모든 태그는 무시되고 리터럴 텍스트로 처리됩니다. 원시 HTML을 렌더링하려면 HTML 콘텐츠를 MarkupString 값으로 래핑합니다. 값은 HTML 또는 SVG로 구문 분석되고 DOM에 삽입됩니다.

Warning

신뢰할 수 없는 출처에서 생성된 원시 HTML을 렌더링하면 보안 위험이 있으므로 항상 피해야 합니다.

다음 예제에서는 MarkupString 형식을 사용하여 정적 HTML 콘텐츠 블록을 구성 요소의 렌더링된 출력에 추가하는 방법을 보여 줍니다.

MarkupStrings.razor:

@page "/markup-strings"

<PageTitle>Markup Strings</PageTitle>

<h1>Markup Strings Example</h1>

@((MarkupString)myMarkup)

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

MarkupStrings.razor:

@page "/markup-strings"

<PageTitle>Markup Strings</PageTitle>

<h1>Markup Strings Example</h1>

@((MarkupString)myMarkup)

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

MarkupStringExample.razor:

@page "/markup-string-example"

@((MarkupString)myMarkup)

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

MarkupStringExample.razor:

@page "/markup-string-example"

@((MarkupString)myMarkup)

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

MarkupStringExample.razor:

@page "/markup-string-example"

@((MarkupString)myMarkup)

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

MarkupStringExample.razor:

@page "/markup-string-example"

@((MarkupString)myMarkup)

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

Razor 템플릿

렌더링 조각은 UI 코드 조각을 정의하는 Razor 템플릿 구문을 사용하여 정의할 수 있습니다. Razor 템플릿은 다음과 같은 형식을 사용합니다.

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

다음 예제에서는 RenderFragmentRenderFragment<TValue> 값을 지정하고 구성 요소에서 직접 템플릿을 렌더링하는 방법을 보여 줍니다. 렌더링 조각은 템플릿 구성 요소에 인수로 전달될 수도 있습니다.

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

이전 코드의 렌더링된 출력:

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

정적 자산

Blazor는 정적 자산에 대한 ASP.NET Core 앱의 규칙을 따릅니다. 정적 자산은 프로젝트의 web root(wwwroot) 폴더 또는 wwwroot 폴더 아래의 폴더에 있습니다.

기본 상대 경로(/)를 사용하여 정적 자산의 웹 루트를 참조합니다. 다음 예제에서 logo.png는 실제로 {PROJECT ROOT}/wwwroot/images 폴더에 있습니다. {PROJECT ROOT}는 앱의 프로젝트 루트입니다.

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

구성 요소는 물결표-슬래시 표기법(~/)을 지원하지 않습니다.

앱의 기본 경로를 설정하는 방법에 대한 자세한 내용은 ASP.NET Core Blazor 호스트 및 배포를 참조하세요.

태그 도우미는 구성 요소에서 지원되지 않습니다.

Tag Helpers는 구성 요소에서 지원되지 않습니다. Blazor에서 태그 도우미와 유사한 기능을 제공하려면 대신, 태그 도우미와 동일한 기능을 포함하는 구성 요소를 만들고 해당 구성 요소를 사용합니다.

SVG(Scalable Vector Graphics) 이미지

Blazor는 HTML을 렌더링하므로 SVG(Scalable Vector Graphics) 이미지(.svg)를 비롯한 브라우저 지원 이미지는 <img> 태그를 통해 지원됩니다.

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

마찬가지로, 스타일시트 파일(.css)의 CSS 규칙에서는 SVG 이미지가 지원됩니다.

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

Blazor는 SVG 내 임의 HTML을 표시하는 <foreignObject> 요소를 지원합니다. 이 태그는 임의 HTML, RenderFragment 또는 Razor 구성 요소를 나타낼 수 있습니다.

아래 예제에서는 다음을 보여줍니다.

  • string(@message) 표시
  • <input> 요소와 value 필드가 있는 양방향 바인딩
  • 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;
}

공백 렌더링 동작

지시문을 @preservewhitespacetrue과 함께 사용하지 않는 한 다음과 같은 경우 추가 공백이 제거됩니다.

  • 요소 내의 선행 또는 후행 공백.
  • RenderFragment/RenderFragment<TValue> 매개 변수 내의 선행 또는 후행 공백(예: 다른 구성 요소에 전달된 자식 콘텐츠).
  • C# 코드 블록(예: @if 또는 @foreach)의 앞 또는 뒤에 있는 공백.

white-space: pre와 같은 CSS 규칙을 사용하는 경우 공백 제거는 렌더링된 출력에 영향을 줄 수 있습니다. 성능 최적화를 사용하지 않고 공백을 유지하려면 다음 작업 중 하나를 수행합니다.

  • Razor 파일(.razor) 맨 위에 @preservewhitespace true 지시문을 추가하여 특정 구성 요소에 기본 설정을 적용합니다.
  • _Imports.razor 파일 안에 @preservewhitespace true 지시문을 추가하여 하위 디렉터리 또는 전체 프로젝트에 기본 설정을 적용합니다.

대부분의 경우 앱이 일반적으로 계속해서 정상적으로(그러나 더 빠르게) 동작하므로 수행해야 할 조치가 없습니다. 공백 제거 시 특정 구성 요소에 렌더링 문제가 발생하는 경우에는 해당 구성 요소에서 @preservewhitespace true를 사용하여 이 최적화를 사용하지 않도록 설정합니다.

공백은 구성 요소의 소스 코드에서 유지됩니다. 공백만 있는 텍스트는 시각적 효과가 없는 경우에도 브라우저의 DOM에서 렌더링됩니다.

다음 구성 요소 태그를 살펴보세요.

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

앞의 예제에서는 다음과 같은 불필요한 공백을 렌더링합니다.

  • @foreach 코드 블록의 외부
  • <li> 요소의 주위
  • @item.Text 출력의 주위

100개 항목으로 구성된 목록은 400개가 넘는 공백 영역을 생성합니다. 추가 공백은 렌더링된 출력에 시각적으로 영향을 주지 않습니다.

구성 요소의 정적 HTML을 렌더링하면 태그 안의 공백이 유지되지 않습니다. 예를 들어 구성 요소 Razor 파일(.razor)에서 다음 <img> 태그의 렌더링된 출력을 확인하세요.

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

위의 태그에서 공백은 유지되지 않습니다.

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

루트 구성 요소

루트 Razor 구성 요소(루트 구성 요소)는 앱에서 만든 모든 구성 요소 계층 구조의 첫 번째 구성 요소입니다.

프로젝트 템플릿 App 에서 만든 앱에서 Blazor Web App 구성 요소(App.razor)는 서버 쪽 Program 파일에서 호출에 대해 선언된 형식 매개 변수에 의해 기본 루트 구성 요소로 MapRazorComponents<TRootComponent> 지정됩니다. 다음 예제에서는 프로젝트 템플릿에서 만든 앱의 App 기본값인 루트 구성 요소로 구성 요소를 사용하는 방법을 Blazor 보여줍니다.

app.MapRazorComponents<App>();

참고 항목

구성 요소와 같은 루트 구성 요소를 대화형으로 App 만드는 것은 지원되지 않습니다.

프로젝트 템플릿 App 에서 만든 앱에서 Blazor Server 구성 요소(App.razor)는 구성 요소 태그 도우미를 사용할 Pages/_Host.cshtml 기본 루트 구성 요소로 지정됩니다.

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

프로젝트 템플릿 App 에서 만든 앱에서 Blazor WebAssembly 구성 요소(App.razor)는 파일의 기본 루트 구성 요소 Program 로 지정됩니다.

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

위의 코드에서 CSS 선택기는 #app구성 요소가 다음을 app사용하여 in wwwroot/index.html id 에 대해 <div> 지정되었음을 나타냅니다App.

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

MVC 및 Razor Pages 앱은 구성 요소 태그 도우미를 사용하여 정적으로 렌더링된 Blazor WebAssembly 루트 구성 요소를 등록할 수도 있습니다.

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

정적으로 렌더링된 구성 요소는 앱에만 추가할 수 있습니다. 나중에 제거하거나 업데이트할 수 없습니다.

자세한 내용은 다음 리소스를 참조하세요.