ASP.NET Core Blazor レイアウト
注意
これは、この記事の最新バージョンではありません。 現在のリリースについては、この記事の .NET 8 バージョンを参照してください。
この記事では、Blazor アプリの再利用可能レイアウト コンポーネントの作成方法について説明します。
メニュー、著作権メッセージ、会社のロゴなどの一部のアプリ要素は、通常、アプリの全体的なプレゼンテーションの一部です。 これらの要素のマークアップのコピーをアプリのすべてのコンポーネントに配置するのは、効率的ではありません。 これらの要素のいずれかが更新されるたびに、その要素が使用されているすべてのコンポーネントを更新する必要があります。 この方法は維持するのにコストがかかり、更新が行われなかった場合にコンテンツの一貫性が失われるおそれがあります。 "レイアウト" を使用することで、これらの問題が解決されます。
Blazor レイアウトとは、それを参照するコンポーネントとマークアップを共有する Razor コンポーネントのことです。 レイアウトでは、データ バインディング、依存関係の挿入、およびコンポーネントのその他の機能を使用できます。
レイアウト コンポーネント
レイアウト コンポーネントを作成する
レイアウト コンポーネントを作成するには:
- Razor テンプレートまたは C# コードによって定義された Razor コンポーネントを作成します。 Razor テンプレートが基になっているレイアウト コンポーネントでは、通常の Razor コンポーネントと同じように
.razor
ファイル拡張子が使用されます。 レイアウト コンポーネントはアプリのコンポーネント間で共有されるため、通常はアプリの共有またはレイアウト フォルダーに配置されます。 ただし、レイアウトは、それを使用するコンポーネントにアクセスできる任意の場所に配置できます。 たとえば、それを使用するコンポーネントと同じフォルダーに、レイアウトを配置できます。 - コンポーネントを LayoutComponentBase から継承します。 LayoutComponentBase によって、レイアウト内にレンダリングされるコンテンツの Body プロパティ (RenderFragment 型) が定義されています。
- Razor 構文
@Body
を使用して、コンテンツがレンダリングされるレイアウト マークアップ内の場所を指定します。
注意
RenderFragment の詳細については、ASP.NET Core Razor コンポーネントに関する記事を参照してください。
次の DoctorWhoLayout
コンポーネントには、レイアウト コンポーネント Razor テンプレートが示されています。 レイアウトにより LayoutComponentBase が継承されて、ナビゲーション バー (<nav>...</nav>
) とフッター (<footer>...</footer>
) の間に @Body
が設定されます。
DoctorWhoLayout.razor
:
@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 仕様) を採用しています。
MainLayout.razor
:
@inherits LayoutComponentBase
<div class="page">
<div class="sidebar">
<NavMenu />
</div>
<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>
</main>
</div>
@inherits LayoutComponentBase
<div class="page">
<div class="sidebar">
<NavMenu />
</div>
<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>
</main>
</div>
@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>
@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>
Blazor の CSS 分離機能により、分離された CSS スタイルが MainLayout
コンポーネントに適用されます。 慣例により、スタイルは同じ名前 MainLayout.razor.css
の付随するスタイルシートによって提供されます。 スタイルシートの ASP.NET Core フレームワークの実装を、ASP.NET Core 参照ソース (dotnet/aspnetcore
GitHub リポジトリ) での検査に使用できます。
Note
通常、.NET 参照ソースへのドキュメント リンクを使用すると、リポジトリの既定のブランチが読み込まれます。このブランチは、.NET の次回リリースに向けて行われている現在の開発を表します。 特定のリリースのタグを選択するには、[Switch branches or tags](ブランチまたはタグの切り替え) ドロップダウン リストを使います。 詳細については、「ASP.NET Core ソース コードのバージョン タグを選択する方法」 (dotnet/AspNetCore.Docs #26205) を参照してください。
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) を参照してください。
レイアウトを適用する
コンポーネントにレイアウトを適用する
@page
ディレクティブが使用されているルーティング可能な Razor コンポーネントにレイアウトを適用するには、@layout
Razor ディレクティブを使用します。 コンパイラにより、@layout
が LayoutAttribute に変換され、その属性がコンポーネント クラスに適用されます。
次の Episodes
コンポーネントの内容が、@Body
の位置にある DoctorWhoLayout
に挿入されます。
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>
@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>
) の 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™ 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
コンポーネント (_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
コンポーネントでレイアウトを指定します。 詳細については、次の「アプリに既定のレイアウトを適用する」セクションを参照してください。
アプリに既定のレイアウトを適用する
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 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 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 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
という名前のレイアウト コンポーネントを設定しています。
Note
次の例は Blazor WebAssembly アプリ専用です。Blazor Web Apps では NotFound テンプレート (<NotFound>...</NotFound>
) を使用しないためです。 ただし、フレームワークの破壊的変更を回避するため、下位互換性の目的でテンプレートがサポートされています。 Blazor Web Apps では通常、ブラウザーの組み込みの 404 UI を表示するか、ASP.NET Core のミドルウェア経由で ASP.NET Core サーバーからカスタム 404 ページを返すことによって、不適切な URL 要求を処理します (例: UseStatusCodePagesWithRedirects
/ API ドキュメント)。
App.razor
:
<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>
注意
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
<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>
レンダリングされた次の 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™ 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>
<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 コンポーネントを ASP.NET Core アプリに統合する」をご覧ください。
ルーティング可能なコンポーネントが Razor Pages アプリに統合されている場合、コンポーネントでアプリの共有レイアウトを使用できます。 詳細については、「ASP.NET Core Razor コンポーネントのプリレンダリングと統合を行う」を参照してください。
セクション
子 Razor コンポーネントからレイアウト内のコンテンツを制御するには、「ASP.NET Core Blazor セクション」を参照してください。
その他のリソース
ASP.NET Core feedback
フィードバック
フィードバックの送信と表示