ASP.NET Core Blazor レイアウト

メニュー、著作権メッセージ、会社のロゴなどの一部のアプリ要素は、通常、アプリの全体的なプレゼンテーションの一部です。 これらの要素のマークアップのコピーをアプリのすべてのコンポーネントに配置するのは、効率的ではありません。 これらの要素のいずれかが更新されるたびに、その要素が使用されているすべてのコンポーネントを更新する必要があります。 この方法は維持するのにコストがかかり、更新が行われなかった場合にコンテンツの一貫性が失われるおそれがあります。 "レイアウト" を使用することで、これらの問題が解決されます。

Blazor レイアウトとは、それを参照するコンポーネントとマークアップを共有する Razor コンポーネントのことです。 レイアウトでは、データ バインディング依存関係の挿入、およびコンポーネントのその他の機能を使用できます。

レイアウト コンポーネント

レイアウト コンポーネントを作成する

レイアウト コンポーネントを作成するには:

  • Razor テンプレートまたは C# コードによって定義された Razor コンポーネントを作成します。 Razor テンプレートが基になっているレイアウト コンポーネントでは、通常の Razor コンポーネントと同じように .razor ファイル拡張子が使用されます。 レイアウト コンポーネントはアプリのコンポーネント間で共有されるため、通常はアプリの Shared フォルダーに配置されます。 ただし、レイアウトは、それを使用するコンポーネントにアクセスできる任意の場所に配置できます。 たとえば、それを使用するコンポーネントと同じフォルダーに、レイアウトを配置できます。
  • コンポーネントを LayoutComponentBase から継承します。 LayoutComponentBase によって、レイアウト内にレンダリングされるコンテンツの Body プロパティ (RenderFragment 型) が定義されています。
  • Razor 構文 @Body を使用して、コンテンツがレンダリングされるレイアウト マークアップ内の場所を指定します。

次の DoctorWhoLayout コンポーネントには、レイアウト コンポーネント Razor テンプレートが示されています。 レイアウトにより LayoutComponentBase が継承されて、ナビゲーション バー (<nav>...</nav>) とフッター (<footer>...</footer>) の間に @Body が設定されます。

Shared/DoctorWhoLayout.razor:

@inherits LayoutComponentBase

<header>
    <h1>Doctor Who&trade; Episode Database</h1>
</header>

<nav>
    <a href="masterlist">Master 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 コンポーネントがアプリの既定のレイアウトです。

Shared/MainLayout.razor:

@inherits LayoutComponentBase

<div class="page">
    <div class="sidebar">
        <NavMenu />
    </div>

    <div class="main">
        <div class="top-row px-4">
            <a href="http://blazor.net" target="_blank" class="ml-md-auto">About</a>
        </div>

        <div class="content px-4">
            @Body
        </div>
    </div>
</div>

Blazor の CSS 分離機能により、分離された CSS スタイルが MainLayout コンポーネントに適用されます。 慣例により、スタイルは同じ名前 Shared/MainLayout.razor.css の付随するスタイルシートによって提供されます。 スタイルシートの ASP.NET Core フレームワークの実装を、ASP.NET Core 参照ソース (dotnet/Aspnetcore GitHub リポジトリ) での検査に使用できます。

注意

ASP.NET Core 参照ソースへのドキュメント リンクを使用すると、リポジトリの main ブランチが読み込まれます。このブランチは、ASP.NET Core の次回リリースに向けて行われている製品単位の現在の開発を表します。 別のリリースのブランチを選択するには、 [Switch branches or tags](ブランチまたはタグの切り替え) ドロップダウン リストを使用して、そのブランチを選択します。 たとえば、ASP.NET Core 5.0 リリースの場合は、release/5.0 ブランチを選択します。

レイアウトを適用する

コンポーネントにレイアウトを適用する

@page ディレクティブが使用されているルーティング可能な Razor コンポーネントにレイアウトを適用するには、@layout Razor ディレクティブを使用します。 コンパイラにより、@layoutLayoutAttribute に変換され、その属性がコンポーネント クラスに適用されます。

次の Episodes コンポーネントの内容が、@Body の位置にある DoctorWhoLayout に挿入されます。

Pages/Episodes.razor:

@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 マークアップが、前の DoctorWhoLayout および Episodes コンポーネントによって生成されます。 関連する 2 つのコンポーネントによって提供されるコンテンツに注目するため、余分なマークアップは示されていません。

  • ヘッダー (<header>...</header>) の Doctor Who™ Episode Database という見出し (<h1>...</h1>)、ナビゲーション バー (<nav>...</nav>)、フッター (<footer>...</footer>) の商標情報要素 (<div>...</div>) は、DoctorWhoLayout コンポーネントによって生成されたものです。
  • Episodes という見出し (<h2>...</h2>) とエピソードの一覧 (<ul>...</ul>) は、Episodes コンポーネントによって生成されたものです。
<body>
    <div id="app">
        <header>
            <h1>Doctor Who&trade; 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>

        <h2>Episodes</h2>

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

        <footer>
            Doctor Who is a registered trademark of the BBC. 
            https://www.doctorwho.tv/
        </footer>
    </div>
</body>

コンポーネントでレイアウトを直接指定すると、"既定のレイアウト" がオーバーライドされます。

レイアウトをコンポーネントのフォルダーに適用する

アプリのすべてのフォルダーには、必要に応じて、_Imports.razor という名前のテンプレート ファイルを格納できます。 コンパイラにより、インポート ファイルに指定されたディレクティブが、同じフォルダー内とそのすべてのサブフォルダー内で再帰的にすべての Razor テンプレートに含まれます。 そのため、@layout DoctorWhoLayout が含まれる _Imports.razor ファイルにより、フォルダー内のすべてのコンポーネントで DoctorWhoLayout コンポーネントが確実に使用されます。 フォルダーとサブフォルダー内のすべての Razor コンポーネント (.razor) に、@layout DoctorWhoLayout を繰り返し追加する必要はありません。

_Imports.razor:

@layout DoctorWhoLayout
...

_Imports.razor ファイルは、Razor ビューおよびページに対する _ViewImports.cshtml ファイルに似ていますが、Razor コンポーネント ファイルに限定して適用されます。

_Imports.razor でレイアウトを指定すると、ルーターの既定のアプリ レイアウトとして指定されているレイアウトがオーバーライドされます。これについては、次のセクションで説明します。

警告

Razor @layout ディレクティブをルート _Imports.razor ファイルに追加 しない でください。レイアウトが無限ループになります。 既定のアプリ レイアウトを制御するには、Router コンポーネントでレイアウトを指定します。 詳細については、次の「アプリに既定のレイアウトを適用する」セクションを参照してください。

注意

@layout Razor ディレクティブによってレイアウトが適用されるのは、@page ディレクティブが使用されているルーティング可能な Razor コンポーネントのみです。

アプリに既定のレイアウトを適用する

App コンポーネントの Router コンポーネントで、既定のアプリ レイアウトを指定します。 Blazor プロジェクト テンプレートに基づくアプリからの次の例では、既定のレイアウトが MainLayout コンポーネントに設定されています。

App.razor:

<Router AppAssembly="@typeof(Program).Assembly">
    <Found Context="routeData">
        <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
    </Found>
    <NotFound>
        <p>Sorry, there's nothing at this address.</p>
    </NotFound>
</Router>

Router コンポーネントの詳細については、「ASP.NET Core Blazor のルーティング」を参照してください。

Router コンポーネントで既定のレイアウトとしてレイアウトを指定することは、この記事のこれまでのセクションで説明したように、コンポーネントごとまたはフォルダーごとにレイアウトをオーバーライドできるため、便利な方法です。 レイアウトを使用する最も一般的で柔軟な方法であるため、Router コンポーネントを使用してアプリの既定のレイアウトを設定することをお勧めします。

任意のコンテンツにレイアウトを適用する (LayoutView コンポーネント)

任意の Razor テンプレート コンテンツにレイアウトを設定するには、LayoutView コンポーネントでレイアウトを指定します。 LayoutView は、任意の Razor コンポーネントで使用できます。 次の例では、MainLayout コンポーネントの NotFound テンプレート (<NotFound>...</NotFound>) に ErrorLayout という名前のレイアウト コンポーネントを設定しています。

App.razor:

<Router AppAssembly="@typeof(Program).Assembly">
    <Found Context="routeData">
        <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
    </Found>
    <NotFound>
        <LayoutView Layout="@typeof(ErrorLayout)">
            <h1>Page not found</h1>
            <p>Sorry, there's nothing at this address.</p>
        </LayoutView>
    </NotFound>
</Router>

入れ子になったレイアウト

コンポーネントであるレイアウトを参照し、そこからさらに別のレイアウトを参照することができます。 たとえば、複数レベルのメニュー構造を作成するために、入れ子になったレイアウトを使用します。

次の例に、入れ子になったレイアウトの使用方法を示しています。 「コンポーネントにレイアウトを適用する」セクションで示されている Episodes コンポーネントは、表示するコンポーネントです。 そのコンポーネントで、DoctorWhoLayout コンポーネントが参照されています。

次の DoctorWhoLayout コンポーネントは、この記事の前の方で示した例を変更したバージョンです。 ヘッダー要素とフッター要素が削除され、レイアウトで別のレイアウト ProductionsLayout が参照されています。 Episodes コンポーネントは、DoctorWhoLayout 内の @Body が出現する場所にレンダリングされます。

Shared/DoctorWhoLayout.razor:

@inherits LayoutComponentBase
@layout ProductionsLayout

<h1>Doctor Who&trade; Episode Database</h1>

<nav>
    <a href="episode-masterlist">Master 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>) が存在します。 Episodes コンポーネントが含まれる DoctorWhoLayout は、@Body が出現する場所にレンダリングされます。

Shared/ProductionsLayout.razor:

@inherits LayoutComponentBase

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

<nav>
    <a href="master-production-list">Master 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 マークアップが、前の入れ子になったレイアウトによって生成されます。 関連する 3 つのコンポーネントによって提供される入れ子になったコンテンツに注目するため、余分なマークアップは示されていません。

  • ヘッダー (<header>...</header>)、プロダクション ナビゲーション バー (<nav>...</nav>)、フッター (<footer>...</footer>) の各要素とその内容は、ProductionsLayout コンポーネントから生成されます。
  • Doctor Who™ Episode Database という見出し (<h1>...</h1>)、エピソード ナビゲーション バー (<nav>...</nav>)、商標情報要素 (<div>...</div>) は、DoctorWhoLayout コンポーネントから生成されます。
  • Episodes という見出し (<h2>...</h2>) とエピソードの一覧 (<ul>...</ul>) は、Episodes コンポーネントによって生成されたものです。
<body>
    <div id="app">
        <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>

        <h1>Doctor Who&trade; Episode Database</h1>

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

        <h2>Episodes</h2>

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

        <div>
            Doctor Who is a registered trademark of the BBC. 
            https://www.doctorwho.tv/
        </div>

        <footer>
            Footer of Productions Layout
        </footer>
    </div>
</body>

統合コンポーネントと Razor Pages レイアウトを共有する

ルーティング可能なコンポーネントが Razor Pages アプリに統合されている場合、コンポーネントでアプリの共有レイアウトを使用できます。 詳細については、「ASP.NET Core Razor コンポーネントのプリレンダリングと統合を行う」を参照してください。

その他のリソース

メニュー、著作権メッセージ、会社のロゴなどの一部のアプリ要素は、通常、アプリの全体的なプレゼンテーションの一部です。 これらの要素のマークアップのコピーをアプリのすべてのコンポーネントに配置するのは、効率的ではありません。 これらの要素のいずれかが更新されるたびに、その要素が使用されているすべてのコンポーネントを更新する必要があります。 この方法は維持するのにコストがかかり、更新が行われなかった場合にコンテンツの一貫性が失われるおそれがあります。 "レイアウト" を使用することで、これらの問題が解決されます。

Blazor レイアウトとは、それを参照するコンポーネントとマークアップを共有する Razor コンポーネントのことです。 レイアウトでは、データ バインディング依存関係の挿入、およびコンポーネントのその他の機能を使用できます。

レイアウト コンポーネント

レイアウト コンポーネントを作成する

レイアウト コンポーネントを作成するには:

  • Razor テンプレートまたは C# コードによって定義された Razor コンポーネントを作成します。 Razor テンプレートが基になっているレイアウト コンポーネントでは、通常の Razor コンポーネントと同じように .razor ファイル拡張子が使用されます。 レイアウト コンポーネントはアプリのコンポーネント間で共有されるため、通常はアプリの Shared フォルダーに配置されます。 ただし、レイアウトは、それを使用するコンポーネントにアクセスできる任意の場所に配置できます。 たとえば、それを使用するコンポーネントと同じフォルダーに、レイアウトを配置できます。
  • コンポーネントを LayoutComponentBase から継承します。 LayoutComponentBase によって、レイアウト内にレンダリングされるコンテンツの Body プロパティ (RenderFragment 型) が定義されています。
  • Razor 構文 @Body を使用して、コンテンツがレンダリングされるレイアウト マークアップ内の場所を指定します。

次の DoctorWhoLayout コンポーネントには、レイアウト コンポーネント Razor テンプレートが示されています。 レイアウトにより LayoutComponentBase が継承されて、ナビゲーション バー (<nav>...</nav>) とフッター (<footer>...</footer>) の間に @Body が設定されます。

Shared/DoctorWhoLayout.razor:

@inherits LayoutComponentBase

<header>
    <h1>Doctor Who&trade; Episode Database</h1>
</header>

<nav>
    <a href="masterlist">Master 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 コンポーネントがアプリの既定のレイアウトです。

Shared/MainLayout.razor:

@inherits LayoutComponentBase

<div class="page">
    <div class="sidebar">
        <NavMenu />
    </div>

    <div class="main">
        <div class="top-row px-4">
            <a href="http://blazor.net" target="_blank" class="ml-md-auto">About</a>
        </div>

        <div class="content px-4">
            @Body
        </div>
    </div>
</div>

Blazor の CSS 分離機能により、分離された CSS スタイルが MainLayout コンポーネントに適用されます。 慣例により、スタイルは同じ名前 Shared/MainLayout.razor.css の付随するスタイルシートによって提供されます。 スタイルシートの ASP.NET Core フレームワークの実装を、ASP.NET Core 参照ソース (dotnet/Aspnetcore GitHub リポジトリ) での検査に使用できます。

注意

ASP.NET Core 参照ソースへのドキュメント リンクを使用すると、リポジトリの main ブランチが読み込まれます。このブランチは、ASP.NET Core の次回リリースに向けて行われている製品単位の現在の開発を表します。 別のリリースのブランチを選択するには、 [Switch branches or tags](ブランチまたはタグの切り替え) ドロップダウン リストを使用して、そのブランチを選択します。 たとえば、ASP.NET Core 5.0 リリースの場合は、release/5.0 ブランチを選択します。

レイアウトを適用する

コンポーネントにレイアウトを適用する

@page ディレクティブが使用されているルーティング可能な Razor コンポーネントにレイアウトを適用するには、@layout Razor ディレクティブを使用します。 コンパイラにより、@layoutLayoutAttribute に変換され、その属性がコンポーネント クラスに適用されます。

次の Episodes コンポーネントの内容が、@Body の位置にある DoctorWhoLayout に挿入されます。

Pages/Episodes.razor:

@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 マークアップが、前の DoctorWhoLayout および Episodes コンポーネントによって生成されます。 関連する 2 つのコンポーネントによって提供されるコンテンツに注目するため、余分なマークアップは示されていません。

  • ヘッダー (<header>...</header>) の Doctor Who™ Episode Database という見出し (<h1>...</h1>)、ナビゲーション バー (<nav>...</nav>)、フッター (<footer>...</footer>) の商標情報要素 (<div>...</div>) は、DoctorWhoLayout コンポーネントによって生成されたものです。
  • Episodes という見出し (<h2>...</h2>) とエピソードの一覧 (<ul>...</ul>) は、Episodes コンポーネントによって生成されたものです。
<body>
    <div id="app">
        <header>
            <h1>Doctor Who&trade; 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>

        <h2>Episodes</h2>

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

        <footer>
            Doctor Who is a registered trademark of the BBC. 
            https://www.doctorwho.tv/
        </footer>
    </div>
</body>

コンポーネントでレイアウトを直接指定すると、"既定のレイアウト" がオーバーライドされます。

レイアウトをコンポーネントのフォルダーに適用する

アプリのすべてのフォルダーには、必要に応じて、_Imports.razor という名前のテンプレート ファイルを格納できます。 コンパイラにより、インポート ファイルに指定されたディレクティブが、同じフォルダー内とそのすべてのサブフォルダー内で再帰的にすべての Razor テンプレートに含まれます。 そのため、@layout DoctorWhoLayout が含まれる _Imports.razor ファイルにより、フォルダー内のすべてのコンポーネントで DoctorWhoLayout コンポーネントが確実に使用されます。 フォルダーとサブフォルダー内のすべての Razor コンポーネント (.razor) に、@layout DoctorWhoLayout を繰り返し追加する必要はありません。

_Imports.razor:

@layout DoctorWhoLayout
...

_Imports.razor ファイルは、Razor ビューおよびページに対する _ViewImports.cshtml ファイルに似ていますが、Razor コンポーネント ファイルに限定して適用されます。

_Imports.razor でレイアウトを指定すると、ルーターの既定のアプリ レイアウトとして指定されているレイアウトがオーバーライドされます。これについては、次のセクションで説明します。

警告

Razor @layout ディレクティブをルート _Imports.razor ファイルに追加 しない でください。レイアウトが無限ループになります。 既定のアプリ レイアウトを制御するには、Router コンポーネントでレイアウトを指定します。 詳細については、次の「アプリに既定のレイアウトを適用する」セクションを参照してください。

注意

@layout Razor ディレクティブによってレイアウトが適用されるのは、@page ディレクティブが使用されているルーティング可能な Razor コンポーネントのみです。

アプリに既定のレイアウトを適用する

App コンポーネントの Router コンポーネントで、既定のアプリ レイアウトを指定します。 Blazor プロジェクト テンプレートに基づくアプリからの次の例では、既定のレイアウトが MainLayout コンポーネントに設定されています。

App.razor:

<Router AppAssembly="@typeof(Program).Assembly">
    <Found Context="routeData">
        <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
    </Found>
    <NotFound>
        <p>Sorry, there's nothing at this address.</p>
    </NotFound>
</Router>

注意

ASP.NET Core 5.0.1 のリリースと、その他の 5.x リリースでは、Router コンポーネントに @trueに設定された PreferExactMatches パラメーターが含まれています。 詳細については、「ASP.NET Core 3.1 から 5.0 への移行」を参照してください。

Router コンポーネントの詳細については、「ASP.NET Core Blazor のルーティング」を参照してください。

Router コンポーネントで既定のレイアウトとしてレイアウトを指定することは、この記事のこれまでのセクションで説明したように、コンポーネントごとまたはフォルダーごとにレイアウトをオーバーライドできるため、便利な方法です。 レイアウトを使用する最も一般的で柔軟な方法であるため、Router コンポーネントを使用してアプリの既定のレイアウトを設定することをお勧めします。

任意のコンテンツにレイアウトを適用する (LayoutView コンポーネント)

任意の Razor テンプレート コンテンツにレイアウトを設定するには、LayoutView コンポーネントでレイアウトを指定します。 LayoutView は、任意の Razor コンポーネントで使用できます。 次の例では、MainLayout コンポーネントの NotFound テンプレート (<NotFound>...</NotFound>) に ErrorLayout という名前のレイアウト コンポーネントを設定しています。

App.razor:

<Router AppAssembly="@typeof(Program).Assembly">
    <Found Context="routeData">
        <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
    </Found>
    <NotFound>
        <LayoutView Layout="@typeof(ErrorLayout)">
            <h1>Page not found</h1>
            <p>Sorry, there's nothing at this address.</p>
        </LayoutView>
    </NotFound>
</Router>

注意

ASP.NET Core 5.0.1 のリリースと、その他の 5.x リリースでは、Router コンポーネントに @trueに設定された PreferExactMatches パラメーターが含まれています。 詳細については、「ASP.NET Core 3.1 から 5.0 への移行」を参照してください。

入れ子になったレイアウト

コンポーネントであるレイアウトを参照し、そこからさらに別のレイアウトを参照することができます。 たとえば、複数レベルのメニュー構造を作成するために、入れ子になったレイアウトを使用します。

次の例に、入れ子になったレイアウトの使用方法を示しています。 「コンポーネントにレイアウトを適用する」セクションで示されている Episodes コンポーネントは、表示するコンポーネントです。 そのコンポーネントで、DoctorWhoLayout コンポーネントが参照されています。

次の DoctorWhoLayout コンポーネントは、この記事の前の方で示した例を変更したバージョンです。 ヘッダー要素とフッター要素が削除され、レイアウトで別のレイアウト ProductionsLayout が参照されています。 Episodes コンポーネントは、DoctorWhoLayout 内の @Body が出現する場所にレンダリングされます。

Shared/DoctorWhoLayout.razor:

@inherits LayoutComponentBase
@layout ProductionsLayout

<h1>Doctor Who&trade; Episode Database</h1>

<nav>
    <a href="episode-masterlist">Master 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>) が存在します。 Episodes コンポーネントが含まれる DoctorWhoLayout は、@Body が出現する場所にレンダリングされます。

Shared/ProductionsLayout.razor:

@inherits LayoutComponentBase

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

<nav>
    <a href="master-production-list">Master 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 マークアップが、前の入れ子になったレイアウトによって生成されます。 関連する 3 つのコンポーネントによって提供される入れ子になったコンテンツに注目するため、余分なマークアップは示されていません。

  • ヘッダー (<header>...</header>)、プロダクション ナビゲーション バー (<nav>...</nav>)、フッター (<footer>...</footer>) の各要素とその内容は、ProductionsLayout コンポーネントから生成されます。
  • Doctor Who™ Episode Database という見出し (<h1>...</h1>)、エピソード ナビゲーション バー (<nav>...</nav>)、商標情報要素 (<div>...</div>) は、DoctorWhoLayout コンポーネントから生成されます。
  • Episodes という見出し (<h2>...</h2>) とエピソードの一覧 (<ul>...</ul>) は、Episodes コンポーネントによって生成されたものです。
<body>
    <div id="app">
        <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>

        <h1>Doctor Who&trade; Episode Database</h1>

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

        <h2>Episodes</h2>

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

        <div>
            Doctor Who is a registered trademark of the BBC. 
            https://www.doctorwho.tv/
        </div>

        <footer>
            Footer of Productions Layout
        </footer>
    </div>
</body>

統合コンポーネントと Razor Pages レイアウトを共有する

ルーティング可能なコンポーネントが Razor Pages アプリに統合されている場合、コンポーネントでアプリの共有レイアウトを使用できます。 詳細については、「ASP.NET Core Razor コンポーネントのプリレンダリングと統合を行う」を参照してください。

その他のリソース

メニュー、著作権メッセージ、会社のロゴなどの一部のアプリ要素は、通常、アプリの全体的なプレゼンテーションの一部です。 これらの要素のマークアップのコピーをアプリのすべてのコンポーネントに配置するのは、効率的ではありません。 これらの要素のいずれかが更新されるたびに、その要素が使用されているすべてのコンポーネントを更新する必要があります。 この方法は維持するのにコストがかかり、更新が行われなかった場合にコンテンツの一貫性が失われるおそれがあります。 "レイアウト" を使用することで、これらの問題が解決されます。

Blazor レイアウトとは、それを参照するコンポーネントとマークアップを共有する Razor コンポーネントのことです。 レイアウトでは、データ バインディング依存関係の挿入、およびコンポーネントのその他の機能を使用できます。

レイアウト コンポーネント

レイアウト コンポーネントを作成する

レイアウト コンポーネントを作成するには:

  • Razor テンプレートまたは C# コードによって定義された Razor コンポーネントを作成します。 Razor テンプレートが基になっているレイアウト コンポーネントでは、通常の Razor コンポーネントと同じように .razor ファイル拡張子が使用されます。 レイアウト コンポーネントはアプリのコンポーネント間で共有されるため、通常はアプリの Shared フォルダーに配置されます。 ただし、レイアウトは、それを使用するコンポーネントにアクセスできる任意の場所に配置できます。 たとえば、それを使用するコンポーネントと同じフォルダーに、レイアウトを配置できます。
  • コンポーネントを LayoutComponentBase から継承します。 LayoutComponentBase によって、レイアウト内にレンダリングされるコンテンツの Body プロパティ (RenderFragment 型) が定義されています。
  • Razor 構文 @Body を使用して、コンテンツがレンダリングされるレイアウト マークアップ内の場所を指定します。

次の DoctorWhoLayout コンポーネントには、レイアウト コンポーネント Razor テンプレートが示されています。 レイアウトにより LayoutComponentBase が継承されて、ナビゲーション バー (<nav>...</nav>) とフッター (<footer>...</footer>) の間に @Body が設定されます。

Shared/DoctorWhoLayout.razor:

@inherits LayoutComponentBase

<header>
    <h1>Doctor Who&trade; Episode Database</h1>
</header>

<nav>
    <a href="masterlist">Master 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 コンポーネントがアプリの既定のレイアウトです。

Shared/MainLayout.razor:

@inherits LayoutComponentBase

<div class="sidebar">
    <NavMenu />
</div>

<div class="main">
    <div class="top-row px-4">
        <a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>
    </div>

    <div class="content px-4">
        @Body
    </div>
</div>

レイアウトを適用する

コンポーネントにレイアウトを適用する

@page ディレクティブが使用されているルーティング可能な Razor コンポーネントにレイアウトを適用するには、@layout Razor ディレクティブを使用します。 コンパイラにより、@layoutLayoutAttribute に変換され、その属性がコンポーネント クラスに適用されます。

次の Episodes コンポーネントの内容が、@Body の位置にある DoctorWhoLayout に挿入されます。

Pages/Episodes.razor:

@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 マークアップが、前の DoctorWhoLayout および Episodes コンポーネントによって生成されます。 関連する 2 つのコンポーネントによって提供されるコンテンツに注目するため、余分なマークアップは示されていません。

  • ヘッダー (<header>...</header>) の Doctor Who™ Episode Database という見出し (<h1>...</h1>)、ナビゲーション バー (<nav>...</nav>)、フッター (<footer>...</footer>) の商標情報要素 (<div>...</div>) は、DoctorWhoLayout コンポーネントによって生成されたものです。
  • Episodes という見出し (<h2>...</h2>) とエピソードの一覧 (<ul>...</ul>) は、Episodes コンポーネントによって生成されたものです。
<body>
    <div id="app">
        <header>
            <h1>Doctor Who&trade; 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>

        <h2>Episodes</h2>

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

        <footer>
            Doctor Who is a registered trademark of the BBC. 
            https://www.doctorwho.tv/
        </footer>
    </div>
</body>

コンポーネントでレイアウトを直接指定すると、"既定のレイアウト" がオーバーライドされます。

レイアウトをコンポーネントのフォルダーに適用する

アプリのすべてのフォルダーには、必要に応じて、_Imports.razor という名前のテンプレート ファイルを格納できます。 コンパイラにより、インポート ファイルに指定されたディレクティブが、同じフォルダー内とそのすべてのサブフォルダー内で再帰的にすべての Razor テンプレートに含まれます。 そのため、@layout DoctorWhoLayout が含まれる _Imports.razor ファイルにより、フォルダー内のすべてのコンポーネントで DoctorWhoLayout コンポーネントが確実に使用されます。 フォルダーとサブフォルダー内のすべての Razor コンポーネント (.razor) に、@layout DoctorWhoLayout を繰り返し追加する必要はありません。

_Imports.razor:

@layout DoctorWhoLayout
...

_Imports.razor ファイルは、Razor ビューおよびページに対する _ViewImports.cshtml ファイルに似ていますが、Razor コンポーネント ファイルに限定して適用されます。

_Imports.razor でレイアウトを指定すると、ルーターの既定のアプリ レイアウトとして指定されているレイアウトがオーバーライドされます。これについては、次のセクションで説明します。

警告

Razor @layout ディレクティブをルート _Imports.razor ファイルに追加 しない でください。レイアウトが無限ループになります。 既定のアプリ レイアウトを制御するには、Router コンポーネントでレイアウトを指定します。 詳細については、次の「アプリに既定のレイアウトを適用する」セクションを参照してください。

@layout Razor ディレクティブによってレイアウトが適用されるのは、@page ディレクティブが使用されているルーティング可能な Razor コンポーネントのみです。

アプリに既定のレイアウトを適用する

App コンポーネントの Router コンポーネントで、既定のアプリ レイアウトを指定します。 Blazor プロジェクト テンプレートに基づくアプリからの次の例では、既定のレイアウトが MainLayout コンポーネントに設定されています。

App.razor:

<Router AppAssembly="@typeof(Program).Assembly">
    <Found Context="routeData">
        <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
    </Found>
    <NotFound>
        <p>Sorry, there's nothing at this address.</p>
    </NotFound>
</Router>

Router コンポーネントの詳細については、「ASP.NET Core Blazor のルーティング」を参照してください。

Router コンポーネントで既定のレイアウトとしてレイアウトを指定することは、この記事のこれまでのセクションで説明したように、コンポーネントごとまたはフォルダーごとにレイアウトをオーバーライドできるため、便利な方法です。 レイアウトを使用する最も一般的で柔軟な方法であるため、Router コンポーネントを使用してアプリの既定のレイアウトを設定することをお勧めします。

任意のコンテンツにレイアウトを適用する (LayoutView コンポーネント)

任意の Razor テンプレート コンテンツにレイアウトを設定するには、LayoutView コンポーネントでレイアウトを指定します。 LayoutView は、任意の Razor コンポーネントで使用できます。 次の例では、MainLayout コンポーネントの NotFound テンプレート (<NotFound>...</NotFound>) に ErrorLayout という名前のレイアウト コンポーネントを設定しています。

App.razor:

<Router AppAssembly="@typeof(Program).Assembly">
    <Found Context="routeData">
        <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
    </Found>
    <NotFound>
        <LayoutView Layout="@typeof(ErrorLayout)">
            <h1>Page not found</h1>
            <p>Sorry, there's nothing at this address.</p>
        </LayoutView>
    </NotFound>
</Router>

入れ子になったレイアウト

コンポーネントであるレイアウトを参照し、そこからさらに別のレイアウトを参照することができます。 たとえば、複数レベルのメニュー構造を作成するために、入れ子になったレイアウトを使用します。

次の例に、入れ子になったレイアウトの使用方法を示しています。 「コンポーネントにレイアウトを適用する」セクションで示されている Episodes コンポーネントは、表示するコンポーネントです。 そのコンポーネントで、DoctorWhoLayout コンポーネントが参照されています。

次の DoctorWhoLayout コンポーネントは、この記事の前の方で示した例を変更したバージョンです。 ヘッダー要素とフッター要素が削除され、レイアウトで別のレイアウト ProductionsLayout が参照されています。 Episodes コンポーネントは、DoctorWhoLayout 内の @Body が出現する場所にレンダリングされます。

Shared/DoctorWhoLayout.razor:

@inherits LayoutComponentBase
@layout ProductionsLayout

<h1>Doctor Who&trade; Episode Database</h1>

<nav>
    <a href="episode-masterlist">Master 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>) が存在します。 Episodes コンポーネントが含まれる DoctorWhoLayout は、@Body が出現する場所にレンダリングされます。

Shared/ProductionsLayout.razor:

@inherits LayoutComponentBase

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

<nav>
    <a href="master-production-list">Master 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 マークアップが、前の入れ子になったレイアウトによって生成されます。 関連する 3 つのコンポーネントによって提供される入れ子になったコンテンツに注目するため、余分なマークアップは示されていません。

  • ヘッダー (<header>...</header>)、プロダクション ナビゲーション バー (<nav>...</nav>)、フッター (<footer>...</footer>) の各要素とその内容は、ProductionsLayout コンポーネントから生成されます。
  • Doctor Who™ Episode Database という見出し (<h1>...</h1>)、エピソード ナビゲーション バー (<nav>...</nav>)、商標情報要素 (<div>...</div>) は、DoctorWhoLayout コンポーネントから生成されます。
  • Episodes という見出し (<h2>...</h2>) とエピソードの一覧 (<ul>...</ul>) は、Episodes コンポーネントによって生成されたものです。
<body>
    <div id="app">
        <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>

        <h1>Doctor Who&trade; Episode Database</h1>

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

        <h2>Episodes</h2>

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

        <div>
            Doctor Who is a registered trademark of the BBC. 
            https://www.doctorwho.tv/
        </div>

        <footer>
            Footer of Productions Layout
        </footer>
    </div>
</body>

統合コンポーネントと Razor Pages レイアウトを共有する

ルーティング可能なコンポーネントが Razor Pages アプリに統合されている場合、コンポーネントでアプリの共有レイアウトを使用できます。 詳細については、「ASP.NET Core Razor コンポーネントのプリレンダリングと統合を行う」を参照してください。

その他のリソース