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" ディレクティブが記述されているコンポーネントによって、このルートが処理されます。

上記の例の 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 サイトのどのセクションを現在表示中なのか理解するのに役立ちます。

自分の知識をチェックする

1.

Blazor コンポーネント内で URI の場所情報を取得するには、どのようなコンポーネントを使用する必要がありますか?

2.

NavLink で現在の URL が参照されているときに、NavLink コンポーネントによってアンカー タグに追加される既定の CSS クラスは何ですか?