ルーティング を用いたアプリ内での画面遷移
- _ダッシュボード_ビューを追加します。
- _ヒーロー_ビューと、_ダッシュボード_ビュー間で画面遷移させます。
- ヒーロー名クリックで詳細画面へ遷移させます。
- アプリの外からアプリのURLを開いたとき、該当の画面を表示させます。
Blazorのルーティング
Angularには、モジュール内での画面遷移を設定するためのルーティングモジュールがありました。
Blazorは、コンポーネントの先頭に @page "パス"
と書くだけでルーティングできます。
Heroes
コンポーネントをページにする
Heroes.razor
ファイルを移動します(移動しなくてもよいです)。
git mv BlazorTourOfHeroes/Shared/Heroes.razor BlazorTourOfHeroes/Pages/Heroes.razor
ファイルの先頭に@page
を追加してパスを設定します。
@page "/heroes"
トップページにリンクを追加する
トップページを書き換えてHeroes
コンポーネントへのリンクを追加します。
リンクは<NavLink>
タグを使います。
@page "/"
<h1>Tour of Heroes</h1>
<nav>
<NavLink href="heroes">Heroes</NavLink>
</nav>
<Message></Message>
ダッシュボードビューを追加する
Pagesディレクトリ以下にコンポーネントを作成します。
dotnet new razorcomponent -o BlazorTourOfHeroes/Pages -n Dashboard
@page "/dashboard"
@using BlazorTourOfHeroes.Model
@using BlazorTourOfHeroes.Service
@inject IHeroService HeroService
<h3>Top Heroes</h3>
<div class="grid grid-pad">
@foreach (var hero in heroes)
{
<a class="col-1-4">
<div class="module hero">
<h4>@hero.Name</h4>
</div>
</a>
}
</div>
@code {
private IEnumerable<Hero> heroes;
protected override async Task OnInitializedAsync()
{
await GetHeroesAsync();
}
private async Task GetHeroesAsync()
{
heroes = (await HeroService.GetHeroes()).Take(5);
}
}
内容はHeroes
コンポーネントととほぼほぼ同じです。
LINQを使用して、先頭5つのみを取得するようにしています。
private async Task GetHeroesAsync()
{
heroes = (await HeroService.GetHeroes()).Take(5);
}
ダッシュボードへのパス
先頭にある@page
で決めています。
@page "/dashboard"
トップページにリンクを追加する
トップページを書き換えて、ダッシュボードへのリンクを追加します。
<h1>Tour of Heroes</h1>
<nav>
<NavLink href="dashboard">Dashboard</NavLink>
<NavLink href="heroes">Heroes</NavLink>
</nav>
<Message></Message>
ヒーロー詳細へのナビゲーション
以下の箇所からヒーロー詳細を表示できるようにします。
- ダッシュボードのヒーロー
- ヒーロー一覧のヒーロー
- アドレスバーへ入力したURL
Heroes
コンポーネントからヒーロー詳細を削除する
Heroes
コンポーネントから<HeroDetail>
タグを削除します。
ヒーロー詳細のパスを決める
HeroDetail
コンポーネントを移動します(しなくてもよいです)。
git mv BlazorTourOfHeroes/Shared/HeroDetail.razor BlazorTourOfHeroes/Pages/HeroDetail.razor
@page
を追加します。Id:int
として、int型以外を受け取らないようにします。
@page "/detail/{Id:int}"
Dashboard
コンポーネントからのリンク
URLにパラメータを含めるようにします。
@foreach (var hero in heroes)
{
<NavLink href="@("detail/" + hero.Id)" class="col-1-4">
<div class="module hero">
<h4>@hero.Name</h4>
</div>
</NavLink>
}
Heroes
コンポーネントからのリンク
Heroes
コンポーネントのヒーロー要素は、以下のようにクリックイベント付きの<li>
になっています。置き換えます。
@foreach (var hero in heroes)
{
<li @onclick="@(_ => OnSelect(hero))"
class="@(selectedHero == hero ? "selected" : "")"
><span class="badge">@hero.Id</span> @hero.Name
</li>
}
foreach
と<li>
はそのままにリンクにします。
@foreach (var hero in heroes)
{
<li>
<NavLink href="@("detail/" + hero.Id)">
<span class="badge">@hero.Id</span> @hero.Name
</NavLink>
</li>
}
不要になったコードを削除する(しなくてもよいです)
Heroes
コンポーネントのonSelect
周りの処理は不要になったので削除します。
private List<Hero> heroes;
private async Task GetHeroesAsync()
{
heroes = await HeroService.GetHeroes();
}
protected override async Task OnInitializedAsync()
{
await GetHeroesAsync();
}
HeroDetail
コンポーネントへルーティングできるようにする
Heroes
コンポーネントから HeroDetail
コンポーネントのhero
プロパティをセットしてヒーローを表示するようにしていました。
HeroDetail
コンポーネントを変更し、URL中のID値からヒーローを表示するようにします。
HeroDetail
コンポーネントでHeroService
を使えるようにします。
@using BlazorTourOfHeroes.Service
@inject IHeroService HeroService
ルートパラメータからIDを受け取る
プロパティに[Parameter]
をつけると、ルートパラメータを受け取れます。
[Parameter]
public int Id { get; set; }
受け取ったIDからヒーローを読み込みます。
Hero Hero { get; set; }
protected override async Task OnInitializedAsync()
{
await GetHeroAsync();
}
private async Task GetHeroAsync()
{
this.Hero = await HeroService.GetHeroAsync(this.Id);
}
HeroService
にGetHeroAsync
メソッドを追加する
IDから単一のヒーローを返すメソッドを追加します。
public Task<Hero> GetHeroAsync(int id)
{
// TODO: ヒーロー達を取得した __後で__ メッセージを送るようにする
messageService.Add($"HeroService: fetched hero id={id}");
var hero = MockHeroes.Create().FirstOrDefault(x => x.Id == id);
return Task.FromResult(hero);
}
こんなんできました
ブラウザのアドレスバーに http://localhost:5000/detail/11
と入力します。
Dr. Niceが表示されます。
前画面に戻れるようにする
詳細から一覧やダッシュボードに戻れるようにします。
「戻る」ボタンを追加します。
<button @onclick="GoBackAsync">戻る</button>
AngularのようなLocationサービスはないようなので、いつものJavaScript window.history.back(-1)
を呼ぶようにします。
JSRuntime
をインジェクトします。
@inject IJSRuntime JSRuntime
window.history.back(-1)
を呼ぶようにします。
private async void GoBackAsync()
{
await JSRuntime.InvokeVoidAsync("history.back", -1);
}