Blazor ルーター コンポーネントを使用してアプリのナビゲーションを制御する
Blazor のルーティング システムには、ユーザー要求を処理し、ユーザーが望む情報を返すことができるコンポーネントに、ユーザー要求が確実に到達できるようにするための柔軟性の高いオプションが用意されています。
あなたは、宅配ピザ会社の Web サイトに関する作業を行っているとします。 ピザの詳細とカスタム トッピングの詳細の要求が両方とも同じコンポーネントによって処理されるようにサイトを設定する必要があります。 このフェーズは完了しましたが、テストではトッピング要求がエラー メッセージを受け取っていることを示しています。 この問題を修正する必要があります。
ここでは、@page
ディレクティブを使用して Blazor でルートを構成する方法について学習します。
Note
このユニットのコード ブロックは実例です。 次のユニットで、独自のコードを記述します。
ルート テンプレートの使用
ユーザーが Web アプリからページを要求するときには、何を表示するかを、URI 内の情報によって指定できます。 次に例を示します。
http://www.contoso.com/pizzas/margherita?extratopping=pineapple
この URI では、プロトコルと Web サイトのアドレスの後に、ユーザーがマルゲリータ ピザについて知りたがっていることが示されます。 また、疑問符の後のクエリ文字列は、お客様がパイナップルの追加トッピングに興味があることを示しています。 Blazor では、ルーティングを使用して、各要求が最適に応答できるコンポーネントに確実に送信されるようにします。 また、ルーティングを使用して、ユーザーが望むものを表示するために必要なすべての情報がコンポーネントに確実に含まれるようにします。 この場合、要求を Pizzas コンポーネントに送信し、追加するパイナップルに関する情報と共にそのコンポーネントでマルゲリータ ピザを表示することができます。
Blazor では、Router コンポーネントという名前の特殊なコンポーネントによって要求をルーティングします。 コンポーネントは、次のように App.razor で構成されます。
<Router AppAssembly="@typeof(Program).Assembly">
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
</Found>
<NotFound>
<p>Sorry, we haven't found any pizzas here.</p>
</NotFound>
</Router>
アプリが起動すると、Blazor によって AppAssembly
属性がチェックされて、どのアセンブリをスキャンする必要があるかが調べられます。 RouteAttribute が存在するコンポーネントがあるか、そのアセンブリがスキャンされます。 Blazor ではこれらの値を使用して、要求をコンポーネントにルーティングする方法を指定する RouteData オブジェクトをコンパイルします。 アプリをコード化するときには、各コンポーネントで @page
ディレクティブを使用して RouteAttribute を修正します。
上記のコードでは、<Found>
タグで、実行時にルーティングを処理するコンポーネントとして RouteView コンポーネントが指定されています。 このコンポーネントが、RouteData オブジェクトと、URI またはクエリ文字列からのすべてのパラメーターを受け取ります。 これが次に、指定されたコンポーネントとそのレイアウトをレンダリングします。 <Found>
タグを使用して既定のレイアウトを指定できます。これが使用されるのは、選択されたコンポーネントで、@layout
ディレクティブによるレイアウトの指定が行われていない場合です。 レイアウトについては、このモジュールで後ほど詳しく学習します。
<Router>
コンポーネントでは、<NotFound>
タグを使用して、一致するルートがない場合にユーザーに何を返すかを指定することもできます。 上記の例では 1 つの <p>
段落が返されますが、複雑な HTML をレンダリングすることが可能です。 たとえば、ホーム ページへのリンクや、サイト管理者あての問い合わせページが含まれる場合があります。
@page ディレクティブの使用
Blazor コンポーネントでは、@page
ディレクティブにより、コンポーネントで要求を直接処理する必要があることを指定します。 RouteAttribute は、それを文字列として渡すことで @page
ディレクティブ内に指定できます。 たとえば、この属性では、ページで /Pizzas ルートへの要求を処理することを指定します。
@page "/Pizzas"
コンポーネントへのルートを複数指定する場合は、この例のように、@page
ディレクティブを 2 つ以上使用します。
@page "/Pizzas"
@page "/CustomPizzas"
場所情報の取得と NavigationManager による移動
ユーザーが要求する、http://www.contoso.com/pizzas/margherita/?extratopping=pineapple
のような URI を処理するコンポーネントを作成するとします。
コンポーネントの作成中には、次のようなナビゲーション情報にアクセスする必要がある場合があります。
- 現在の完全な URI (
http://www.contoso.com/pizzas/margherita?extratopping=pineapple
など)。 - ベース URI (
http://www.contoso.com/
など)。 - ベース相対パス (
pizzas/margherita
など)。 - クエリ文字列 (
?extratopping=pineapple
など)。
これらの値はすべて、NavigationManager
オブジェクトを使用して取得できます。 このオブジェクトをコンポーネントに挿入する必要があります。その後、そのプロパティにアクセスできます。 このコードでは、NavigationManager
オブジェクトを使用して Web サイトのベース URI を取得してから、それを使用してホーム ページへのリンクを設定しています。
@page "/pizzas"
@inject NavigationManager NavManager
<h1>Buy a Pizza</h1>
<p>I want to order a: @PizzaName</p>
<a href=@HomePageURI>Home Page</a>
@code {
[Parameter]
public string PizzaName { get; set; }
public string HomePageURI { get; set; }
protected override void OnInitialized()
{
HomePageURI = NavManager.BaseUri;
}
}
クエリ文字列にアクセスするには、完全 URI を解析する必要があります。 この解析を実行するには、Microsoft.AspNetCore.WebUtilities
アセンブリの QueryHelpers
クラスを使用します。
@page "/pizzas"
@using Microsoft.AspNetCore.WebUtilities
@inject NavigationManager NavManager
<h1>Buy a Pizza</h1>
<p>I want to order a: @PizzaName</p>
<p>I want to add this topping: @ToppingName</p>
@code {
[Parameter]
public string PizzaName { get; set; }
private string ToppingName { get; set; }
protected override void OnInitialized()
{
var uri = NavManager.ToAbsoluteUri(NavManager.Uri);
if (QueryHelpers.ParseQuery(uri.Query).TryGetValue("extratopping", out var extraTopping))
{
ToppingName = System.Convert.ToString(extraTopping);
}
}
}
上記のコンポーネントが展開された状態でユーザーが URI http://www.contoso.com/pizzas?extratopping=Pineapple
を要求すると、レンダリングされたページに "このトッピングを追加希望: パイナップル" というメッセージが表示されます。
コード内で NavigationManager
オブジェクトを使用し、NavigationManager.NavigateTo()
メソッドを呼び出して、ユーザーを別のコンポーネントに送信することもできます。
@page "/pizzas/{pizzaname}"
@inject NavigationManager NavManager
<h1>Buy a Pizza</h1>
<p>I want to order a: @PizzaName</p>
<button class="btn" @onclick="NavigateToPaymentPage">
Buy this pizza!
</button>
@code {
[Parameter]
public string PizzaName { get; set; }
private void NavigateToPaymentPage()
{
NavManager.NavigateTo("buypizza");
}
}
Note
NavigateTo()
メソッドに渡す文字列は、絶対 URI または相対 URI で、ユーザーの送信先です。 そのアドレスにコンポーネントが設定されている必要があります。 上記のコードの場合、@page "/buypizza"
ディレクティブが記述されているコンポーネントによって、このルートが処理されます。
NavLink コンポーネントを使用する
上記の例の 1 つでは、NavigationManager.BaseUri
値を取得し、それを使用して <a>
タグの href
属性をホーム ページに設定するためにコードが使用されました。 Blazor では NavLink コンポーネントを使用して <a>
タグをレンダリングする必要があります。リンクの href
属性が現在の URL と一致する場合は、このコンポーネントによって active
CSS クラスが切り替えられるためです。 active
クラスのスタイルを設定することで、どのナビゲーション リンクが現在のページ用であるかをユーザーに明示できます。
そのため、NavLink を使用する場合のホーム ページのリンク例は、次のコードのようになります。
@page "/pizzas"
@inject NavigationManager NavManager
<h1>Buy a Pizza</h1>
<p>I want to order a: @PizzaName</p>
<NavLink href=@HomePageURI Match="NavLinkMatch.All">Home Page</NavLink>
@code {
[Parameter]
public string PizzaName { get; set; }
public string HomePageURI { get; set; }
protected override void OnInitialized()
{
HomePageURI = NavManager.BaseUri;
}
}
NavLink コンポーネントの Match
属性は、いつリンクを強調表示するかを管理するために使用されます。 2 つのオプションがあります。
- NavLinkMatch.All: この値を使用する場合、リンクがアクティブなリンクとして強調表示されるのは、その
href
が現在の URL 全体と一致するときだけです。 - NavLinkMatch.Prefix: この値を使用する場合、リンクがアクティブなリンクとして強調表示されるのは、その
href
が現在の URL の最初の部分と一致するときです。 たとえば、<NavLink href="pizzas" Match="NavLinkMatch.Prefix">
というリンクがあったとします。 このリンクがアクティブとして強調表示されるのは、現在の URL がhttp://www.contoso.com/pizzas
であった場合の、その URL 内の任意の場所 (http://www.contoso.com/pizzas/formaggio
など) に対してです。 この動作は、ユーザーが、Web サイトのどのセクションを現在表示中なのか理解するのに役立ちます。