瀏覽器是一個最熟悉的導向模型應用了,輸入一個 URL 地址後瀏覽器導引至相應 URL 頁面,點擊網頁上的連結接導至另一個新的頁面,瀏覽器的「前一頁」或「後一頁」可以導航至我們瀏覽器的歷史頁面。
Angular 組件路由就是藉用這個模型,可以理解為透過瀏覽器的網址來生成使用者看到的介面,並通過一些可選參數指定當前顯示哪些畫面。當然也可以把路由綁定至一個畫面組件裡,當點擊連結時,導至適合的畫面。並且記錄在瀏覽器歷史列表,方便瀏覽器前往下個或回到上個工作。
在網頁應用程式中, 可以在 index.html
中可以設定 <base>
元件來設定根目錄。
<base href="/">
使用 Angular 時候,我們要導入模組 @angular/router
import { ROUTER_PROVIDERS } from '@angular/router';
Angular 透過 RouteDefinition
來設定 URL 給瀏覽器查詢,而一般路由會設定在 Parent Component (父元件),然後透過 @Routes
裝飾器來註冊路由。
@Component({ ... })
@Routes([
{path: '/crisis-center', component: CrisisListComponent},
{path: '/heroes', component: HeroListComponent},
{path: '/hero/:id', component: HeroDetailComponent}
])
export class AppComponent implements OnInit {
constructor(private router: Router) {}
ngOnInit() {
// 導向 crisis-center 頁面
this.router.navigate(['/crisis-center']);
}
}
@Routes
裡面第三種用法是用來參數傳址,/:id
用來輸入參數,例如 /hero/58
現在我們已經知道如何配置路由,當瀏覽器請求 URL 地址:/heroes
時,路由會查找 RouteDefinition
匹配到 HeroListComponent
,那麼匹配到的組件放在哪呢?我們就需要在目前 Component 中 template 裡加入 RouterOutlet
。
<router-outlet></router-outlet>
在模板裡可以用 routerLink
來導向,用陣列包起來是因為還可以傳參數。
//app.component.html
<h1>Component Router</h1>
<nav>
<a [routerLink]="['/crisis-center']">Crisis Center</a>
<a [routerLink]="['/heroes']">Heroes</a>
<!-- 也可以不是陣列
<a routerLink="/crisis-center" routerLinkActive="active">Crisis Center</a>
<a routerLink="/heroes" routerLinkActive="active">Heroes</a>
-->
</nav>
<router-outlet></router-outlet>
看起來就會長這樣
假設要傳參數的話就這樣用
模板:
<h1 class="title">Angular Router</h1>
<nav>
<a [routerLink]="['/crisis-center']">Crisis Center</a>
<a [routerLink]="['/crisis-center/1', { foo: 'foo' }]">Dragon Crisis</a>
<a [routerLink]="['/crisis-center/2']">Shark Crisis</a>
</nav>
<router-outlet></router-outlet>
程式碼跳轉:
this.router.navigate(['/hero', hero.id]);
假設有個頁面必須要登入才能夠看到,也就是要經過認證才能瀏覽頁面,那麼未登入的人就會被導向登入頁面。
姑且稱這種服務叫做認證守衛,我們在根目錄寫一個守衛,這樣其他頁面之後都可以用。
//auth-guard.service.ts
import { Injectable } from '@angular/core';
import { CanActivate } from '@angular/router';
@Injectable()
export class AuthGuard implements CanActivate {
canActivate() {
console.log('AuthGuard#canActivate called');
return true;
}
}
這便只是讓守衛 log 訊息,並回傳 true
讓導向繼續。
接著就可以使用我們的 canActivate
保護措施
//admin/admin-routing.module.ts
import { AuthGuard } from '../auth-guard.service';
const adminRoutes: Routes = [
{
path: 'admin',
component: AdminComponent,
canActivate: [AuthGuard],
children: [
{
path: '',
children: [
{ path: 'crises', component: ManageCrisesComponent },
{ path: 'heroes', component: ManageHeroesComponent },
{ path: '', component: AdminDashboardComponent }
],
}
]
}
];
@NgModule({
imports: [
RouterModule.forChild(adminRoutes)
],
exports: [
RouterModule
]
})
export class AdminRoutingModule {}
這樣子我們簡單的守衛便有保護到 admin
這個頁面了。
若要更貼切真實一點的守衛樣貌的話,大概會長這樣
//auth-guard.service.ts
import { Injectable } from '@angular/core';
import {
CanActivate, Router,
ActivatedRouteSnapshot,
RouterStateSnapshot
} from '@angular/router';
import { AuthService } from './auth.service';
@Injectable()
export class AuthGuard implements CanActivate {
constructor(private authService: AuthService, private router: Router) {}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
let url: string = state.url;
return this.checkLogin(url);
}
checkLogin(url: string): boolean {
if (this.authService.isLoggedIn) { return true; }
// 儲存現在的 URL,這樣登入後可以直接回來這個頁面
this.authService.redirectUrl = url;
// 導回登入頁面
this.router.navigate(['/login']);
return false;
}
}
是說在以前angular1的環境底下routing真的寫得不好,所以紛紛轉去ui-router,很推薦ui-router-ng2這個套件做routing,全部state更棒!