前言

瀏覽器是一個最熟悉的導向模型應用了,輸入一個 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

Router Outlet

現在我們已經知道如何配置路由,當瀏覽器請求 URL 地址:/heroes 時,路由會查找 RouteDefinition 匹配到 HeroListComponent,那麼匹配到的組件放在哪呢?我們就需要在目前 Component 中 template 裡加入 RouterOutlet

<router-outlet></router-outlet>

路由連結 (Router Links)

在模板裡可以用 routerLink 來導向,用陣列包起來是因為還可以傳參數。

//app.component.html

<h1>Component Router</h1>
<nav>
<a [routerLink]="['/crisis-center']">Crisis Center</a>
<a [routerLink]="['/heroes']">Heroes</a>

&lt;!-- &#x4E5F;&#x53EF;&#x4EE5;&#x4E0D;&#x662F;&#x9663;&#x5217;
&lt;a routerLink=&quot;/crisis-center&quot; routerLinkActive=&quot;active&quot;&gt;Crisis Center&lt;/a&gt;
&lt;a routerLink=&quot;/heroes&quot; routerLinkActive=&quot;active&quot;&gt;Heroes&lt;/a&gt;
--&gt;

</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; }

// &#x5132;&#x5B58;&#x73FE;&#x5728;&#x7684; URL&#xFF0C;&#x9019;&#x6A23;&#x767B;&#x5165;&#x5F8C;&#x53EF;&#x4EE5;&#x76F4;&#x63A5;&#x56DE;&#x4F86;&#x9019;&#x500B;&#x9801;&#x9762;
this.authService.redirectUrl = url;

// &#x5C0E;&#x56DE;&#x767B;&#x5165;&#x9801;&#x9762;
this.router.navigate([&apos;/login&apos;]);
return false;

}
}