Layoutという仕組みを使って、共通ヘッダーを定義するやり方を説明します。
公式ドキュメントに沿いつつご紹介します。
環境
VS2022のBlazor Appテンプレートからプロジェクトを作成します。
Render Modeはどれを選択しても大丈夫です。
Layout Componentの作り方
@inherits LayoutComponentBase
を継承してください。
@Body
にComponentが描画されます。
シンプル化のため、本記事では記載していないですが、Layout Componentも他のComponentと同様に@code
を持つことができますので、イベント処理なども当然行うことができます。
@inherits LayoutComponentBase
<h1>Custom Layout</h1>
@Body
Application全体に反映させたい場合
Routes.razor
のRouteView
に設定します。
<Router AppAssembly="typeof(Program).Assembly" AdditionalAssemblies="new[] { typeof(Client._Imports).Assembly }">
<Found Context="routeData">
@* DefaultLayoutに適用 *@
<RouteView RouteData="routeData" DefaultLayout="typeof(Layout.CustomLayout)" />
<FocusOnNavigate RouteData="routeData" Selector="h1" />
</Found>
</Router>
フォルダごとに反映させたい場合
_Imports.razor
ファイルの特性を活かします。
このファイルに記載されたDirectiveは、_Imports.razor
ファイルが存在するフォルダと、そのフォルダ以下全てのRazor Componentに適用されます。
Directiveの一つとして、@layout
をすることで、指定フォルダとその配下のすべての@page
を持つComponentに、共通Layoutを適用させることができます。
例えば、管理者用 Layoutと一般ユーザー用 Layoutを分けたい場合は、以下のような実装で実現可能です。
- Layout
@inherits LayoutComponentBase
<h1>Admin Layout</h1>
@Body
@inherits LayoutComponentBase
<h1>Member Layout</h1>
@Body
_Imports.razor
@layout BlazorAppTips.Components.Layout.AdminLayout
@layout BlazorAppTips.Components.Layout.MemberLayout
- Component
@page "/admin"
<h3>Admin Component</h3>
@page "/member"
<h3>Member Component</h3>
- Tree
├─Layout
│ AdminLayout.razor
│ MemberLayout.razor
└─Pages
├─Admin
│ AdminComponent.razor
│ _Imports.razor
│
└─Member
MemberComponent.razor
_Imports.razor
個別のComponentにLayoutを適用する場合
@layout
Directiveを対象のComponentに記載すればOKです。
そのComponentのみにLayoutが適用されます。
特定のContentのみに適用する場合
<LayoutView>
Componentを利用し、以下のように実装可能です。
例えば、Default Layoutを適用させつつ、一部のContentにのみ特定のLayoutを適用したいときに利用できます。
@page "/"
<div>Home</div>
<LayoutView Layout="typeof(ErrorLayout)">
<h1>Nested content</h1>
<h2>Hello</h2>
</LayoutView>
Nested Layouts
Lyout Componentに更に@layout
Directiveを追加することで、Layoutを積み重ねることが可能です。
上述した、フォルダごと、ComponentごとのLayout適用はDefault Layoutを上書きします。
例えば、を維持しつつ、フォルダごとにLayoutを適用させたいという場合は、以下のように記載することで実現できます。実務でも発生するケースですね。
フォルダごとにLayout Componentを適用させた場合、<RouteView RouteData="routeData" DefaultLayout="typeof(Layout.CustomLayout)" />
で指定されているDefaultLayout
が上書きされるため、明示的にフォルダごとに適用されるLayout Componentに@layout
Directiveを設定します。
- Layout
@inherits LayoutComponentBase
@layout CustomLayout
<h2>NestedLayout</h2>
@Body
_Imports.razor
@layout BlazorAppTips.Components.Layout.NestedLayout
- Component
@page "/nested"
<h3>Component</h3>
- Tree
├─Layout
│ CustomLayout.razor
│ NestedLayout.razor
└─Pages
├─Nested
│ Component.razor
│ _Imports.razor
Layout Componentが見つからない?
名前空間
いくつかの方法で対象Layout(razor component)の名前空間を適用させることができます。
※BlazorAppTips
がプロジェクト名の場合です。
- Root配下の_Imports.razorに
@using
を追加
@using BlazorAppTips.Components.Layout
-
@using
と@layout
で名前空間とComponentを同時に指定
@using BlazorAppTips.Components.Layout
@layout CustomLayout
-
@layout
に名前空間とComponentをまとめて指定
@layout BlazorAppTips.Components.Layout.CustomLayout
最後に
Layout Componentを利用することで、Componentの再利用性が高まります。
これにRender Modeが絡んでくると厄介で、Layout Component、Routes.razor
Componentを.Client
プロジェクト側に移動する必要などが出てきます。また別の機会にそれらのユースケースは説明できればと思います。