다음을 통해 공유


ASP.NET Core Blazor 레이아웃

참고

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

경고

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

중요한

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

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

이 문서에서는 Blazor 앱의 재사용 가능한 레이아웃 구성 요소를 만드는 방법을 설명합니다.

레이아웃의 Blazor 유용성

메뉴, 저작권 메시지, 회사 로고 등의 일부 앱 요소는 일반적으로 앱의 전반적인 표현의 일부입니다. 이러한 요소의 태그 복사본을 앱의 모든 구성 요소에 배치하는 것은 효율적이지 않습니다. 요소 중 하나가 업데이트될 때마다 해당 요소를 사용하는 모든 구성 요소를 업데이트해야 하기 때문입니다. 이 방법은 유지 관리 비용이 많이 들고 업데이트가 누락된 경우 일관성 없는 콘텐츠가 될 수 있습니다. ‘레이아웃’은 이 문제를 해결합니다.

Blazor 레이아웃은 Razor 구성 요소로, 이를 참조하는 구성 요소와 마크업을 공유합니다. 레이아웃은 데이터 바인딩, 종속성 주입, 구성 요소의 기타 기능을 사용할 수 있습니다.

레이아웃 구성 요소 만들기

레이아웃 구성 요소를 만들려면:

  • Razor 템플릿 또는 C# 코드로 정의된 Razor 구성 요소를 만듭니다. Razor 템플릿을 기반으로 하는 레이아웃 구성 요소는 일반 .razor 구성 요소와 마찬가지로 Razor 파일 확장자를 사용합니다. 레이아웃 구성 요소는 앱의 구성 요소 간에 공유되므로 일반적으로 앱 Shared 또는 Layout 폴더에 배치됩니다. 그러나 레이아웃은 이를 사용하는 구성 요소에 액세스할 수 있는 곳이면 어디에나 배치할 수 있습니다. 예를 들어 레이아웃을 사용하는 구성 요소와 동일한 폴더에 레이아웃을 배치할 수 있습니다.
  • LayoutComponentBase에서 구성 요소를 상속합니다. LayoutComponentBase는 레이아웃 내부에 렌더링된 콘텐츠의 Body 속성(RenderFragment 형식)을 정의합니다.
  • Razor 구문 @Body를 사용하여 콘텐츠가 렌더링되는 위치를 레이아웃 태그에 지정합니다.

참고

RenderFragment에 대한 자세한 내용은 ASP.NET Core Razor 구성 요소를 참조하세요.

다음 DoctorWhoLayout 구성 요소는 레이아웃 구성 요소의 Razor 템플릿을 보여 줍니다. 레이아웃은 LayoutComponentBase를 상속하고 탐색 모음(@Body)과 바닥글(<nav>...</nav>) 사이에 <footer>...</footer>를 설정합니다.

DoctorWhoLayout.razor:

@inherits LayoutComponentBase

<PageTitle>Doctor Who® Database</PageTitle>

<header>
    <h1>Doctor Who® Database</h1>
</header>

<nav>
    <a href="main-list">Main Episode List</a>
    <a href="search">Search</a>
    <a href="new">Add Episode</a>
</nav>

@Body

<footer>
    @TrademarkMessage
</footer>

@code {
    public string TrademarkMessage { get; set; } =
        "Doctor Who is a registered trademark of the BBC. " +
        "https://www.doctorwho.tv/ https://www.bbc.com";
}
@inherits LayoutComponentBase

<PageTitle>Doctor Who® Database</PageTitle>

<header>
    <h1>Doctor Who® Database</h1>
</header>

<nav>
    <a href="main-list">Main Episode List</a>
    <a href="search">Search</a>
    <a href="new">Add Episode</a>
</nav>

@Body

<footer>
    @TrademarkMessage
</footer>

@code {
    public string TrademarkMessage { get; set; } =
        "Doctor Who is a registered trademark of the BBC. " +
        "https://www.doctorwho.tv/ https://www.bbc.com";
}
@inherits LayoutComponentBase

<header>
    <h1>Doctor Who™ Episode Database</h1>
</header>

<nav>
    <a href="main-list">Main Episode List</a>
    <a href="search">Search</a>
    <a href="new">Add Episode</a>
</nav>

@Body

<footer>
    @TrademarkMessage
</footer>

@code {
    public string TrademarkMessage { get; set; } = 
        "Doctor Who is a registered trademark of the BBC. " +
        "https://www.doctorwho.tv/";
}
@inherits LayoutComponentBase

<header>
    <h1>Doctor Who™ Episode Database</h1>
</header>

<nav>
    <a href="main-list">Main Episode List</a>
    <a href="search">Search</a>
    <a href="new">Add Episode</a>
</nav>

@Body

<footer>
    @TrademarkMessage
</footer>

@code {
    public string TrademarkMessage { get; set; } = 
        "Doctor Who is a registered trademark of the BBC. " +
        "https://www.doctorwho.tv/";
}
@inherits LayoutComponentBase

<header>
    <h1>Doctor Who™ Episode Database</h1>
</header>

<nav>
    <a href="main-list">Main Episode List</a>
    <a href="search">Search</a>
    <a href="new">Add Episode</a>
</nav>

@Body

<footer>
    @TrademarkMessage
</footer>

@code {
    public string TrademarkMessage { get; set; } = 
        "Doctor Who is a registered trademark of the BBC. " +
        "https://www.doctorwho.tv/";
}
@inherits LayoutComponentBase

<header>
    <h1>Doctor Who™ Episode Database</h1>
</header>

<nav>
    <a href="main-list">Main Episode List</a>
    <a href="search">Search</a>
    <a href="new">Add Episode</a>
</nav>

@Body

<footer>
    @TrademarkMessage
</footer>

@code {
    public string TrademarkMessage { get; set; } = 
        "Doctor Who is a registered trademark of the BBC. " +
        "https://www.doctorwho.tv/";
}

MainLayout 구성 요소

Blazor 프로젝트 템플릿에서 만든 앱에서 MainLayout 구성 요소는 앱의 기본 레이아웃입니다. Blazor의 레이아웃은 Flexbox layout model을 채택합니다(W3C 사양).

Blazor의 CSS 격리 기능은 격리된 CSS 스타일을 MainLayout 구성 요소에 적용합니다. 규칙에 따라 스타일은 동일한 이름의 동반 스타일시트 MainLayout.razor.css에 의해 제공됩니다. 스타일시트의 ASP.NET Core 프레임워크 구현은 ASP.NET Core 참조 원본(dotnet/aspnetcore GitHub repository)에서 검사할 수 있습니다.

참고

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

Blazor의 CSS 격리 기능은 격리된 CSS 스타일을 MainLayout 구성 요소에 적용합니다. 규칙에 따라 스타일은 동일한 이름의 동반 스타일시트 MainLayout.razor.css에 의해 제공됩니다.

정적으로 렌더링된 레이아웃 구성 요소

Blazor Web App 페이지별/구성 요소 렌더링을 채택하는 경우(Routes구성 요소가 대화형 렌더링 모드를 지정하지 않음) 레이아웃 구성 요소는 서버에서 정적으로 렌더링됩니다. 레이아웃에 대화형 렌더 모드를 직접 적용하는 것은 지원되지 않습니다. 이는 Blazor가 루트 구성 요소 매개 변수로 RenderFragment (@Body의 경우) 를 직렬화하는 것을 지원하지 않기 때문입니다. 예를 들어 구성 요소 맨 @rendermode InteractiveServer 위에 배치 MainLayout 하면 다음과 같은 런타임 예외가 발생합니다.

System.InvalidOperationException: rendermode 'InteractiveServerRenderMode'를 사용하여 'Body' 매개 변수를 구성 요소 'MainLayout'에 전달할 수 없습니다. 매개 변수가 임의의 코드이며 serialize할 수 없는 대리자 형식 'Microsoft.AspNetCore.Components.RenderFragment'이기 때문입니다.

이는 페이지별/구성 요소 렌더링을 채택하는 앱에서 LayoutComponentBase 상속되는 모든 레이아웃 구성 요소에 적용됩니다.

이 시나리오는 이후 릴리스 Blazor에서 해결될 수 있습니다. 자세한 내용은 [Blazor] SSR에서 렌더링 조각 직렬화 지원(dotnet/aspnetcore #52768)을 참조하세요. 그 동안 페이지별/구성 요소 렌더링을 채택하는 Blazor Web App 방식으로 다음 접근 방식을 채택할 수 있습니다.

대화형 작업을 수행할 수 있는 래퍼 구성 요소를 만듭니다. 다음 예제에서 래퍼 구성 요소는 자식 구성 요소에서 콘텐츠를 받을 수 있는 Blazor 섹션을 포함하고 있습니다.

파일에서 _Imports.razor 섹션에 대한 지시문을 @using 추가합니다(Microsoft.AspNetCore.Components.Sections).

@using Microsoft.AspNetCore.Components.Sections

Pages 폴더에 다음 대화형 래퍼 구성 요소를 만드세요.

Pages/InteractiveWrapper.razor:

@rendermode InteractiveServer

<div>
    <SectionOutlet SectionName="top-bar" />
</div>

@ChildContent

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

Counter 구성 요소는 래퍼 구성 요소를 사용하고 대화형 섹션 콘텐츠를 설정할 수 있습니다. 다음 예제에서는 카운터 단추가 섹션에 배치됩니다.

Pages/Counter.razor:

@page "/counter"
@rendermode InteractiveServer

<InteractiveWrapper>

    <SectionContent SectionName="top-bar">
        <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
    </SectionContent>

    <PageTitle>Counter</PageTitle>

    <h1>Counter</h1>

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

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

</InteractiveWrapper>

@code {
    private int currentCount = 0;

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

앱 주변의 다른 구성 요소는 구성 요소의 InteractiveWrapper 콘텐츠를 래핑하고 대화형 섹션 콘텐츠를 설정할 수도 있습니다.

레이아웃 적용

레이아웃 네임스페이스를 사용할 수 있도록 설정

프레임워크에 대해 시간이 지남에 따라 레이아웃 파일 위치와 네임스페이스가 변경되었습니다. 빌드하는 앱의 BlazorBlazor 버전 및 유형에 따라 레이아웃의 네임스페이스를 사용할 때 표시해야 할 수 있습니다. 레이아웃 구현을 참조할 때 레이아웃의 네임스페이스를 표시하지 않고 레이아웃을 찾을 수 없는 경우 다음 방법 중 어느 것이든 수행합니다.

  • @using 레이아웃의 위치에 대한 지시문을 _Imports.razor 파일에 추가합니다. 다음 예제에서는 이름이 Layout 있는 레이아웃 폴더가 폴더 내에 Components 있고 앱의 네임스페이스는 다음과 같습니다 BlazorSample.

    @using BlazorSample.Components.Layout
    
  • 구성 요소 정의의 맨 위에 레이아웃이 사용된다는 @using 지시문을 추가하십시오.

    @using BlazorSample.Components.Layout
    @layout DoctorWhoLayout
    
  • 사용되는 레이아웃의 네임스페이스를 정규화합니다.

    @layout BlazorSample.Components.Layout.DoctorWhoLayout
    

구성 요소에 레이아웃 적용

라우팅 가능한 @layout 구성 요소에 Razor 지시문이 있는 경우, Razor@page 지시문을 사용하여 레이아웃을 적용합니다. 컴파일러는 @layoutLayoutAttribute로 변환하고 구성 요소 클래스에 특성을 적용합니다.

다음 Episodes 구성 요소의 콘텐츠는 DoctorWhoLayout@Body 위치에 삽입됩니다.

Episodes.razor:

@page "/episodes"
@layout DoctorWhoLayout

<h2>Doctor Who® Episodes</h2>

<ul>
    <li>
        <a href="https://www.bbc.co.uk/programmes/p00vfknq">
            <em>The Ribos Operation</em>
        </a>
    </li>
    <li>
        <a href="https://www.bbc.co.uk/programmes/p00vfdsb">
            <em>The Sunmakers</em>
        </a>
    </li>
    <li>
        <a href="https://www.bbc.co.uk/programmes/p00vhc26">
            <em>Nightmare of Eden</em>
        </a>
    </li>
</ul>
@page "/episodes"
@layout DoctorWhoLayout

<h2>Doctor Who® Episodes</h2>

<ul>
    <li>
        <a href="https://www.bbc.co.uk/programmes/p00vfknq">
            <em>The Ribos Operation</em>
        </a>
    </li>
    <li>
        <a href="https://www.bbc.co.uk/programmes/p00vfdsb">
            <em>The Sunmakers</em>
        </a>
    </li>
    <li>
        <a href="https://www.bbc.co.uk/programmes/p00vhc26">
            <em>Nightmare of Eden</em>
        </a>
    </li>
</ul>
@page "/episodes"
@layout DoctorWhoLayout

<h2>Episodes</h2>

<ul>
    <li>
        <a href="https://www.bbc.co.uk/programmes/p00vfknq">
            <em>The Ribos Operation</em>
        </a>
    </li>
    <li>
        <a href="https://www.bbc.co.uk/programmes/p00vfdsb">
            <em>The Sun Makers</em>
        </a>
    </li>
    <li>
        <a href="https://www.bbc.co.uk/programmes/p00vhc26">
            <em>Nightmare of Eden</em>
        </a>
    </li>
</ul>
@page "/episodes"
@layout DoctorWhoLayout

<h2>Episodes</h2>

<ul>
    <li>
        <a href="https://www.bbc.co.uk/programmes/p00vfknq">
            <em>The Ribos Operation</em>
        </a>
    </li>
    <li>
        <a href="https://www.bbc.co.uk/programmes/p00vfdsb">
            <em>The Sun Makers</em>
        </a>
    </li>
    <li>
        <a href="https://www.bbc.co.uk/programmes/p00vhc26">
            <em>Nightmare of Eden</em>
        </a>
    </li>
</ul>
@page "/episodes"
@layout DoctorWhoLayout

<h2>Episodes</h2>

<ul>
    <li>
        <a href="https://www.bbc.co.uk/programmes/p00vfknq">
            <em>The Ribos Operation</em>
        </a>
    </li>
    <li>
        <a href="https://www.bbc.co.uk/programmes/p00vfdsb">
            <em>The Sun Makers</em>
        </a>
    </li>
    <li>
        <a href="https://www.bbc.co.uk/programmes/p00vhc26">
            <em>Nightmare of Eden</em>
        </a>
    </li>
</ul>

다음의 렌더링된 HTML 태그는 이전 DoctorWhoLayoutEpisodes 구성 요소에 의해 생성됩니다. 관련된 두 가지 구성 요소에서 제공하는 콘텐츠에 초점을 맞추기 위해 관련되지 않은 태그는 표시되지 않습니다.

  • 헤더(<h1>...</h1>), 내비게이션 바(<header>...</header>), 그리고 바닥글(<nav>...</nav>)의 상표 정보에 있는 H1 "데이터베이스" 제목은 <footer>...</footer> 구성 요소에서 가져옵니다.
  • H2 "에피소드" 제목(<h2>...</h2>) 및 에피소드 목록(<ul>...</ul>)은 구성 요소에서 Episodes 가져옵니다.
<header>
    <h1 ...>...</h1>
</header>

<nav>
    ...
</nav>

<h2>...</h2>

<ul>
    <li>...</li>
    <li>...</li>
    <li>...</li>
</ul>

<footer>
    ...
</footer>

구성 요소에서 직접 레이아웃을 지정하면 ‘기본 레이아웃’이 대체됩니다.

구성 요소 폴더에 레이아웃 적용

앱의 모든 폴더에 이름이 _Imports.razor인 템플릿 파일을 선택적으로 포함할 수 있습니다. 컴파일러는 imports 파일에 지정된 지시문을 동일한 폴더와 모든 하위 폴더의 모든 Razor 템플릿에 포함합니다. 따라서 _Imports.razor 파일에 @layout DoctorWhoLayout을 포함하면 폴더의 모든 구성 요소가 DoctorWhoLayout 구성 요소를 사용하게 됩니다. 폴더와 하위 폴더에 있는 모든 @layout DoctorWhoLayout 구성 요소(Razor)에 .razor을 반복적으로 추가할 필요가 없습니다.

_Imports.razor:

@layout DoctorWhoLayout
...

_Imports.razor 파일은 Razor 뷰 및 Pages용 _ViewImports.cshtml 파일과 유사하지만, 구체적으로 Razor 구성 요소 파일에 적용됩니다.

_Imports.razor에서 레이아웃을 지정하면 라우터의 기본 앱 레이아웃으로 지정된 레이아웃이 재정의됩니다. 자세한 내용은 다음 섹션에서 설명합니다.

경고

지시문을 루트 Razor 파일에 추가하지 @layout 마십시오. 이것은 레이아웃의 무한 루프를 발생시킵니다. 기본 앱 레이아웃을 제어하려면 Router 구성 요소에서 레이아웃을 지정합니다. 자세한 내용은 다음의 앱에 기본 레이아웃 적용 섹션을 참조하세요.

_Imports.razor 파일을 사용하여 @layout 지시문이 있는 구성 요소 폴더에 레이아웃을 적용할 때와 레이아웃 구성 요소 자체가 _Imports.razor 파일의 동일한 폴더 또는 폴더 계층 구조에 있는 경우 동일한 조건이 발생합니다. 레이아웃 구성 요소에도 @layout 지시문이 적용되므로 레이아웃을 적용하는 무한 루프가 발생합니다. 재귀 문제를 방지하려면 레이아웃 구성 요소를 Layouts 파일이 적용하는 위치와 떨어진 폴더(예: _Imports.razor)에 저장하는 것이 좋습니다.

참고

지시문은 @layout 지시문을 사용하여 라우팅 가능한 Razor 구성 요소에만 레이아웃을 Razor@page 적용합니다.

앱에 기본 레이아웃 적용

Router 구성 요소의 RouteView 구성 요소에서 기본 앱 레이아웃을 지정합니다. 매개 변수를 DefaultLayout 사용하여 레이아웃 유형을 설정합니다.

<RouteView RouteData="routeData" DefaultLayout="typeof({LAYOUT})" />

앞의 예제에서 {LAYOUT} 자리 표시자는 레이아웃을 위한 것입니다(예를 들어, 레이아웃 파일 이름이 DoctorWhoLayout일 경우 DoctorWhoLayout.razor). .NET 버전 및 앱 유형 Blazor 에 따라 레이아웃의 네임스페이스를 식별해야 할 수 있습니다. 자세한 내용은 레이아웃 네임스페이스를 사용 가능하게 하기 섹션을 참조하세요.

Router 구성 요소의 RouteView에서 레이아웃을 기본 레이아웃으로 지정하는 것은 유용한 방법입니다. 이렇게 하면 이 문서의 앞부분에서 설명한 바와 같이 구성 요소별 또는 폴더별로 레이아웃을 재정의할 수 있습니다. Router 구성 요소를 사용하여 앱의 기본 레이아웃을 설정하는 것이 좋습니다. 이것이 레이아웃을 사용하는 가장 일반적이고 유연한 접근 방식이기 때문입니다.

임의의 콘텐츠에 레이아웃 적용(LayoutView 구성 요소)

임의의 Razor 템플릿 콘텐츠에 대한 레이아웃을 설정하려면 LayoutView 구성 요소를 사용하여 레이아웃을 지정합니다. 모든 LayoutView 구성 요소에서 Razor를 사용할 수 있습니다. 다음 예제에서는 ErrorLayout 구성 요소의 MainLayout 템플릿(NotFound)에 대해 이름이 <NotFound>...</NotFound>인 레이아웃 구성 요소를 설정합니다.

<Router ...>
    <Found ...>
        ...
    </Found>
    <NotFound>
        <LayoutView Layout="typeof(ErrorLayout)">
            <h1>Page not found</h1>
            <p>Sorry, there's nothing at this address.</p>
        </LayoutView>
    </NotFound>
</Router>

.NET 버전 및 Blazor 앱 유형에 따라 레이아웃의 네임스페이스를 ID로 지정해야 할 수도 있습니다. 자세한 내용은 레이아웃 네임스페이스를 사용 가능하게 하기 섹션을 참조하세요.

중요한

Blazor Web App는 NotFound 파라미터(<NotFound>...</NotFound> 마크업)를 사용하지 않지만, 프레임워크의 심각한 변경을 피하기 위해 이전 버전과의 호환성을 지원합니다. 서버 쪽 ASP.NET Core 미들웨어 파이프라인은 서버에서 요청을 처리합니다. 서버 쪽 기술을 사용하여 잘못된 요청을 처리합니다. 자세한 내용은 ASP.NET Core Blazor 렌더링 모드를 참조하세요.

참고

.NET 5.0.1 릴리스 및 추가 5.x 릴리스의 경우, Router 구성 요소에는 PreferExactMatches 매개 변수가 @true로 설정됩니다. 자세한 내용은 ASP.NET Core 3.1에서 .NET 5로 마이그레이션을 참조하세요.

중첩된 레이아웃

구성 요소는 레이아웃을 참조할 수 있으며, 그 레이아웃은 또 다른 레이아웃을 참조할 수 있습니다. 예를 들어 중첩된 레이아웃은 여러 수준의 메뉴 구조를 만드는 데 사용됩니다.

다음 예제에서는 중첩된 레이아웃을 사용하는 방법을 보여 줍니다. Episodes 섹션에 표시된 구성 요소가 표시할 구성 요소입니다. 이 구성 요소는 DoctorWhoLayout 구성 요소를 참조합니다.

다음 DoctorWhoLayout 구성 요소는 이 문서의 앞부분에 표시된 예제의 수정된 버전입니다. 머리글 및 바닥글 요소가 제거되고 레이아웃은 다른 레이아웃인 ProductionsLayout을 참조합니다. Episodes에서 @Body가 나타나는 곳에서 DoctorWhoLayout 구성 요소가 렌더링됩니다.

DoctorWhoLayout.razor:

@inherits LayoutComponentBase
@layout ProductionsLayout

<PageTitle>Doctor Who® Database</PageTitle>

<h1>Doctor Who® Database</h1>

<nav>
    <a href="main-episode-list">Main Episode List</a>
    <a href="episode-search">Search</a>
    <a href="new-episode">Add Episode</a>
</nav>

@Body

<div>
    @TrademarkMessage
</div>

@code {
    public string TrademarkMessage { get; set; } =
        "Doctor Who is a registered trademark of the BBC. " +
        "https://www.doctorwho.tv/ https://www.bbc.com";
}
@inherits LayoutComponentBase
@layout ProductionsLayout

<PageTitle>Doctor Who® Database</PageTitle>

<h1>Doctor Who® Database</h1>

<nav>
    <a href="main-episode-list">Main Episode List</a>
    <a href="episode-search">Search</a>
    <a href="new-episode">Add Episode</a>
</nav>

@Body

<div>
    @TrademarkMessage
</div>

@code {
    public string TrademarkMessage { get; set; } =
        "Doctor Who is a registered trademark of the BBC. " +
        "https://www.doctorwho.tv/ https://www.bbc.com";
}
@inherits LayoutComponentBase
@layout ProductionsLayout

<h1>Doctor Who™ Episode Database</h1>

<nav>
    <a href="main-episode-list">Main Episode List</a>
    <a href="episode-search">Search</a>
    <a href="new-episode">Add Episode</a>
</nav>

@Body

<div>
    @TrademarkMessage
</div>

@code {
    public string TrademarkMessage { get; set; } = 
        "Doctor Who is a registered trademark of the BBC. " +
        "https://www.doctorwho.tv/";
}
@inherits LayoutComponentBase
@layout ProductionsLayout

<h1>Doctor Who™ Episode Database</h1>

<nav>
    <a href="main-episode-list">Main Episode List</a>
    <a href="episode-search">Search</a>
    <a href="new-episode">Add Episode</a>
</nav>

@Body

<div>
    @TrademarkMessage
</div>

@code {
    public string TrademarkMessage { get; set; } = 
        "Doctor Who is a registered trademark of the BBC. " +
        "https://www.doctorwho.tv/";
}
@inherits LayoutComponentBase
@layout ProductionsLayout

<h1>Doctor Who™ Episode Database</h1>

<nav>
    <a href="main-episode-list">Main Episode List</a>
    <a href="episode-search">Search</a>
    <a href="new-episode">Add Episode</a>
</nav>

@Body

<div>
    @TrademarkMessage
</div>

@code {
    public string TrademarkMessage { get; set; } = 
        "Doctor Who is a registered trademark of the BBC. " +
        "https://www.doctorwho.tv/";
}
@inherits LayoutComponentBase
@layout ProductionsLayout

<h1>Doctor Who™ Episode Database</h1>

<nav>
    <a href="main-episode-list">Main Episode List</a>
    <a href="episode-search">Search</a>
    <a href="new-episode">Add Episode</a>
</nav>

@Body

<div>
    @TrademarkMessage
</div>

@code {
    public string TrademarkMessage { get; set; } = 
        "Doctor Who is a registered trademark of the BBC. " +
        "https://www.doctorwho.tv/";
}

ProductionsLayout 구성 요소는 이제 머리글(<header>...</header>) 및 바닥글(<footer>...</footer>) 요소가 있는 최상위 레이아웃 요소를 포함합니다. DoctorWhoLayout 구성 요소가 있는 Episodes@Body가 나타나는 곳에서 렌더링됩니다.

ProductionsLayout.razor:

@inherits LayoutComponentBase

<header>
    <h1>Productions</h1>
</header>

<nav>
    <a href="main-production-list">Main Production List</a>
    <a href="production-search">Search</a>
    <a href="new-production">Add Production</a>
</nav>

@Body

<footer>
    Footer of Productions Layout
</footer>
@inherits LayoutComponentBase

<header>
    <h1>Productions</h1>
</header>

<nav>
    <a href="main-production-list">Main Production List</a>
    <a href="production-search">Search</a>
    <a href="new-production">Add Production</a>
</nav>

@Body

<footer>
    Footer of Productions Layout
</footer>
@inherits LayoutComponentBase

<header>
    <h1>Productions</h1>
</header>

<nav>
    <a href="main-production-list">Main Production List</a>
    <a href="production-search">Search</a>
    <a href="new-production">Add Production</a>
</nav>

@Body

<footer>
    Footer of Productions Layout
</footer>
@inherits LayoutComponentBase

<header>
    <h1>Productions</h1>
</header>

<nav>
    <a href="main-production-list">Main Production List</a>
    <a href="production-search">Search</a>
    <a href="new-production">Add Production</a>
</nav>

@Body

<footer>
    Footer of Productions Layout
</footer>
@inherits LayoutComponentBase

<header>
    <h1>Productions</h1>
</header>

<nav>
    <a href="main-production-list">Main Production List</a>
    <a href="production-search">Search</a>
    <a href="new-production">Add Production</a>
</nav>

@Body

<footer>
    Footer of Productions Layout
</footer>
@inherits LayoutComponentBase

<header>
    <h1>Productions</h1>
</header>

<nav>
    <a href="main-production-list">Main Production List</a>
    <a href="production-search">Search</a>
    <a href="new-production">Add Production</a>
</nav>

@Body

<footer>
    Footer of Productions Layout
</footer>

렌더링된 다음 HTML 태그는 이전의 중첩된 레이아웃에 의해 생성됩니다. 관련된 세 가지 구성 요소에서 제공하는 중첩된 콘텐츠에 초점을 맞추기 위해 관련되지 않은 태그는 표시되지 않습니다.

  • 머리글(<header>...</header>), 프로덕션 탐색 모음(<nav>...</nav>), 바닥글(<footer>...</footer>) 요소와 해당 콘텐츠는 ProductionsLayout 구성 요소에서 옵니다.
  • H1 "데이터베이스" 제목(<h1>...</h1>), 에피소드 탐색 모음(<nav>...</nav>), 상표 정보(<div>...</div>)는 DoctorWhoLayout 구성 요소에서 제공됩니다.
  • H2 "에피소드" 제목(<h2>...</h2>) 및 에피소드 목록(<ul>...</ul>)은 구성 요소에서 Episodes 가져옵니다.
<header>
    ...
</header>

<nav>
    <a href="main-production-list">Main Production List</a>
    <a href="production-search">Search</a>
    <a href="new-production">Add Production</a>
</nav>

<h1>...</h1>

<nav>
    <a href="main-episode-list">Main Episode List</a>
    <a href="episode-search">Search</a>
    <a href="new-episode">Add Episode</a>
</nav>

<h2>...</h2>

<ul>
    <li>...</li>
    <li>...</li>
    <li>...</li>
</ul>

<div>
    ...
</div>

<footer>
    ...
</footer>

통합된 구성 요소가 포함된 Razor Pages 레이아웃 공유

라우팅 가능한 구성 요소가 Razor Pages 앱에 통합된 경우 구성 요소와 함께 앱의 공유 레이아웃을 사용할 수 있습니다. 자세한 내용은 MVC 또는 Razor Pages와 ASP.NET Core Razor 구성 요소 통합을 참조하세요.

섹션

자식 Razor 구성 요소에서 레이아웃의 콘텐츠를 제어하려면 ASP.NET Core Blazor 섹션을 참조하세요.

추가 리소스