ASP.NET Core Blazor レイアウト
注意
これは、この記事の最新バージョンではありません。 現在のリリースについては、この記事の .NET 9 バージョンを参照してください。
警告
このバージョンの ASP.NET Core はサポート対象から除外されました。 詳細については、「.NET および .NET Core サポート ポリシー」を参照してください。 現在のリリースについては、この記事の .NET 8 バージョンを参照してください。
重要
この情報はリリース前の製品に関する事項であり、正式版がリリースされるまでに大幅に変更される可能性があります。 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 が継承されて、ナビゲーション バー (<nav>...</nav>
) とフッター (<footer>...</footer>
) の間に @Body
が設定されます。
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 (MDN documentation) (W3C 仕様) を採用しています。
Blazor の CSS 分離機能により、分離された CSS スタイルが MainLayout
コンポーネントに適用されます。 慣例により、スタイルは同じ名前 MainLayout.razor.css
の付随するスタイルシートによって提供されます。 スタイルシートの ASP.NET Core フレームワークの実装を、ASP.NET Core 参照ソース (dotnet/aspnetcore
GitHub リポジトリ) での検査に使用できます。
注意
通常、.NET 参照ソースへのドキュメント リンクを使用すると、リポジトリの既定のブランチが読み込まれます。このブランチは、.NET の次回リリースに向けて行われている現在の開発を表します。 特定のリリースのタグを選択するには、[Switch branches or tags](ブランチまたはタグの切り替え) ドロップダウン リストを使います。 詳細については、「ASP.NET Core ソース コードのバージョン タグを選択する方法」 (dotnet/AspNetCore.Docs #26205) を参照してください。
Blazor の CSS 分離機能により、分離された CSS スタイルが MainLayout
コンポーネントに適用されます。 慣例により、スタイルは同じ名前 MainLayout.razor.css
の付随するスタイルシートによって提供されます。
レイアウトを適用する
レイアウトの名前空間を使用可能にする
レイアウト ファイルの場所と名前空間は、Blazor フレームワークの時間の経過に伴って変更されてきました。 ビルドしているアプリの Blazor バージョンと Blazor の種類によっては、レイアウトの名前空間を使用するときに指定する必要がある場合があります。 レイアウトの実装を参照していて、レイアウトの名前空間の表示がなく、レイアウトが見つからない場合は、次のいずれかの方法を実行します。
レイアウトの場所の
@using
ディレクティブを_Imports.razor
ファイルに追加します。 次の例では、Layout
という名前が付いたレイアウトのフォルダーがComponents
フォルダー内にあり、アプリの名前空間はBlazorSample
です。@using BlazorSample.Components.Layout
レイアウトが使用されるコンポーネント定義の先頭に
@using
ディレクティブを追加します。@using BlazorSample.Components.Layout @layout DoctorWhoLayout
レイアウトが使用される名前空間を完全修飾します。
@layout BlazorSample.Components.Layout.DoctorWhoLayout
コンポーネントにレイアウトを適用する
@page
ディレクティブが使用されているルーティング可能な Razor コンポーネントにレイアウトを適用するには、@layout
Razor ディレクティブを使用します。 コンパイラにより、@layout
が LayoutAttribute に変換され、その属性がコンポーネント クラスに適用されます。
次の Episodes
コンポーネントの内容が、@Body
の位置にある DoctorWhoLayout
に挿入されます。
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 マークアップが、前の DoctorWhoLayout
および Episodes
コンポーネントによって生成されます。 関連する 2 つのコンポーネントによって提供されるコンテンツに注目するため、余分なマークアップは示されていません。
- ヘッダー (
<header>...</header>
) の H1 "database" という見出し (<h1>...</h1>
)、ナビゲーション バー (<nav>...</nav>
)、フッター (<footer>...</footer>
) の商標情報は、DoctorWhoLayout
コンポーネントから生成されます。 - H2 "episodes" という見出し (
<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
ファイルからインポートされた@layout
ディレクティブによって設定されます。 - アプリの既定のレイアウトとして設定します。後の「アプリに既定のレイアウトを適用する」セクションの説明を参照してください。
レイアウトをコンポーネントのフォルダーに適用する
アプリのすべてのフォルダーには、必要に応じて、_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 コンポーネントでレイアウトを指定します。 詳細については、次の「アプリに既定のレイアウトを適用する」セクションを参照してください。
アプリに既定のレイアウトを適用する
Router コンポーネントの RouteView コンポーネントで、既定のアプリ レイアウトを指定します。 DefaultLayout パラメータを使用してレイアウトの種類を設定します。
<RouteView RouteData="routeData" DefaultLayout="typeof({LAYOUT})" />
前の例では、{LAYOUT}
プレースホルダーがレイアウトになります (例: レイアウト ファイル名が DoctorWhoLayout.razor
の場合、DoctorWhoLayout
)。 .NET のバージョンと Blazor アプリの種類によっては、レイアウトの名前空間を表す必要がある場合があります。 詳細については、「レイアウトの名前空間を使用可能にする」セクションを参照してください。
Router コンポーネントの RouteView で既定のレイアウトとしてレイアウトを指定することは、この記事のこれまでのセクションで説明したように、コンポーネントごとまたはフォルダーごとにレイアウトをオーバーライドできるため、便利な方法です。 レイアウトを使用する最も一般的で柔軟な方法であるため、Router コンポーネントを使用してアプリの既定のレイアウトを設定することをお勧めします。
任意のコンテンツにレイアウトを適用する (LayoutView
コンポーネント)
任意の Razor テンプレート コンテンツにレイアウトを設定するには、LayoutView コンポーネントでレイアウトを指定します。 LayoutView は、任意の Razor コンポーネントで使用できます。 次の例では、MainLayout
コンポーネントの NotFound テンプレート (<NotFound>...</NotFound>
) に ErrorLayout
という名前のレイアウト コンポーネントを設定しています。
<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 アプリの種類によっては、レイアウトの名前空間を identity する必要がある場合があります。 詳細については、「レイアウトの名前空間を使用可能にする」セクションを参照してください。
重要
Blazor Web App では NotFound パラメータ (<NotFound>...</NotFound>
マークアップ) は使用しませんが、フレームワークの破壊的変更を回避するため、下位互換性の目的でこのパラメータがサポートされています。 サーバー側の ASP.NET Core ミドルウェア パイプラインは、サーバー上の要求を処理します。 サーバー側の手法を使用して、不適切な要求を処理してください。 詳細については、「ASP.NET Core Blazor レンダリング モード」を参照してください。
Note
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
が出現する場所にレンダリングされます。
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>
) が存在します。 Episodes
コンポーネントが含まれる DoctorWhoLayout
は、@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 マークアップが、前の入れ子になったレイアウトによって生成されます。 関連する 3 つのコンポーネントによって提供される入れ子になったコンテンツに注目するため、余分なマークアップは示されていません。
- ヘッダー (
<header>...</header>
)、プロダクション ナビゲーション バー (<nav>...</nav>
)、フッター (<footer>...</footer>
) の各要素とその内容は、ProductionsLayout
コンポーネントから生成されます。 - H1 "database" という見出し (
<h1>...</h1>
)、エピソード ナビゲーション バー (<nav>...</nav>
)、商標情報 (<div>...</div>
) は、DoctorWhoLayout
コンポーネントから生成されます。 - H2 "episodes" という見出し (
<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 アプリに統合されている場合、コンポーネントでアプリの共有レイアウトを使用できます。 詳細については、「ASP.NET Core Razor コンポーネントを ASP.NET Core アプリに統合する」をご覧ください。
ルーティング可能なコンポーネントが Razor Pages アプリに統合されている場合、コンポーネントでアプリの共有レイアウトを使用できます。 詳細については、「ASP.NET Core Razor コンポーネントのプリレンダリングと統合を行う」を参照してください。
セクション
子 Razor コンポーネントからレイアウト内のコンテンツを制御するには、「ASP.NET Core Blazor セクション」を参照してください。
その他のリソース
ASP.NET Core