本文章將會是閱讀官方文件Add navigation with routing 內容所做的筆記。
接續 Day06 的內容。
在昨天的內容中,我們是透過修改網頁的路由路徑來切換網頁的內容。
但是,我們不可能讓使用者需要藉由這樣的操作,才能看到他想要看到的內容阿。
所以,Angular 提供了 navigation link 類似連結按鈕的功能,讓使用者點擊該連結按鈕之後,網頁就可以被導轉到的他們想要看到的網頁囉。
那我們就在 app.component.html 加入這個導轉的連結按鈕。
<div>
<h1>
{{ title }}
</h1>
<nav>
<a routerLink="/heroes">Hero</a>
</nav>
<router-outlet></router-outlet>
</div>
可以看到 Angular 的導轉連結按鈕是直接用 a 連結做成的,不像 Vue 是特別自製了一個 router-link 的連結按鈕。
在這個 a 連結要附上 routerLink 這個 directive 並將我們在 routing 檔案中設定的 HeroesComponent 的路由路徑 /heroes 設給它,設定完成後,你就可以在畫面中看到出現了一個 Hero 的連結按鈕。
按下去之後,可以看到網頁的 url 被加入了 hero之外 ,畫面中也出現 HeroesComponent 元件的內容囉。
接下來我們要新增 dashboard 的元件,
所以,先輸入指令 ng g c dashboard
,成功創完之後,Angular CLI 會自動幫我們將這個新增的元件引入專案中。
接著,我們要為這個元件設定專屬它的路由
--- app-routing.module.ts ---
import { DashboardComponent } from './dashboard/dashboard.component';
const routes: Routes = [
{ path: 'heroes', component: HeroesComponent },
{ path: 'dashboard', component: DashboardComponent }
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
dashboard 這個元件的內容,是這個專案的首頁,所以,當使用者一進入我們的網頁的時候,第一個畫面會先看到首頁的內容,這個效果就需要設定預設路由來達到囉~
--- app-routing.module.ts ---
import { DashboardComponent } from './dashboard/dashboard.component';
const routes: Routes = [
{ path: 'heroes', component: HeroesComponent },
{ path: 'dashboard', component: DashboardComponent },
{ path: '', redirectTo: '/dashboard', pathMatch: 'full'}
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
加入的程式碼內容的功能為當當下 url 為空白時,網頁路由會被導轉到 /dashboard,並且路徑的內容要完全符合空白(pathMatch: 'full')
,才會執行這個導轉的功能,而當使用者一進入到網頁的時候,通常 url 會是空白的,所以,會直接被導轉到 dashboard 頁面囉。
接著,在 app.component.html 檔案中加入可以將當前頁面導轉到 dashboard 頁面的連結按鈕。
--- app.component.html ---
<div>
<h1>
{{ title }}
</h1>
<nav>
<a routerLink="/heroes">Hero</a>
<a routerLink="/dashboard">DashBoard</a>
</nav>
<router-outlet></router-outlet>
</div>
接下來,我們要透過改變路由,進入到指定路由,進而讓畫面呈現指定英雄的詳細資料。
所以,接下來我們就要來設定路由了
首先,我們先將 HeroesComponent 元件裡面的 app-hero-detail 標籤拿掉,免得會重複出現英雄詳細內容。
第二,到 routing 設定的檔案中,加入以下設定
--- app.routing.module.ts ---
const routes: Routes = [
// ..
{ path: 'detail/:id', component: HeroDetailComponent }, // 呈現詳細資料的路由設定
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
可以看到路由中有一個 :id
可以用來動態設定路由,當我們點擊不一樣的英雄會傳入不一樣的 id 並獲取相對應的資料。
接下來,我們要分別在 dashboard 頁面和 HeroesComponent 頁面中英雄按鈕的 routerLink 路由設定對應路由
--- dashboard.component.html ---
<div class="heroes-menu">
<a *ngFor="let hero of heroes" routerLink="/detail/{{ hero.id }}">
{{ hero.name }}
</a>
</div>
--- heroes.component.html ---
<h2>My Heroes</h2>
<ul class="heroes">
<li *ngFor="let hero of heroes" (click)="onSelect(hero)" [class.selected]="hero === selectedHero">
<a routerLink="/detail/{{hero.id}}">
<span class="badge">{{hero.id}}</span> {{hero.name}}
</a>
</li>
</ul>
因為,現在英雄的詳細資料呈現的功能全權交給 hero-detail 元件來呈現,所以,我們必須為 hero-detail 元件做一個能夠接受傳入的英雄 id 是多少並透過這個 id 來跟資料庫要對應的英雄資料,最後,再將獲取到的資料渲染到畫面中。
首先,我們要引入以下三個模組到 hero-detail 元件中
--- hero-detail.component.ts ---
import { ActivatedRoute } from '@angular/router';
import { Location } from '@angular/common';
import { HeroService } from '../hero.service';
@Component({
// ...
})
export class HeroDetailComponent implements OnInit {
constructor(
private route: ActivatedRoute,
private heroService: HeroService,
private location: Location
) { }
}
ActivatedRoute 模組,元件可以透過這個模組來獲取當下的路由資訊,所以,我們可以藉由它來取出在 url 中,該英雄的 id
HeroService 模組,模仿遠端資料庫,我們會將從 url 中取出來的 id 丟到這個模組中,接著,這個模組就會回傳相對的英雄資訊給我們。
location 模組: 用來操作瀏覽器的模組,像是前一頁、後一頁...等等,之類的功能。
接下來,我們要從 route 中取出 id 資訊。
--- hero-detail.component.ts ---
@Component({
// ...
})
export class HeroDetailComponent implements OnInit {
ngOnInit(): void {
this.getHero();
}
getHero(): void {
const id = Number(this.route.snapshot.paramMap.get('id'));
this.heroService.getHero(id)
.subscribe(hero => this.hero = hero);
}
}
在 ngOnInit 加入 getHero 的內容,可以在當 hero-detail 元件在創建的時候,就執行取得 url 的 id 資訊。
route.snapshot: 會在元件被創建的時候,紀錄該元件當下的 route 資訊
paramMap: 會去紀錄的 route 中取得我們在後面指定的參數內容,像這邊我們就指定要取得 id 參數的內容
最後,取到 id 的資訊之後,就把它丟到 getHero 函式中去得到相對應的英雄資訊,並將其設給 hero-detail 元件的 hero 成員。
設計一個回到上一頁的按鈕在 hero-detail 元件中。
--- hero-detail.component.html ---
<button (click)="goBack">go back</button>
--- hero-detail.component.ts---
goBack(): void {
this.location.back();
}
這邊的內容就可以看到我們透過引入的 location 模組來達到類似像 JS 的 go.back() 讓瀏覽器回上一頁的功能。
這邊做個總結
this.route.snapshot
得到當下元件的路由資訊,再透過 paramMap.get('id')
來取得路由資訊中指定的 id 參數的內容,最後,再將 id 丟到指定函式中,去資料庫取得相對應的內容,再將該內容渲染到頁面上。