iT邦幫忙

2017 iT 邦幫忙鐵人賽
DAY 9
3
Modern Web

Angular 2 之 30 天邁向神乎其技之路系列 第 9

[Day 09] Angular 2 路由

前言

瀏覽器是一個最熟悉的導向模型應用了,輸入一個 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>
    
    <!-- 也可以不是陣列
    <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;
  }
}

上一篇
[Day 08] Angular 2 Lazy Loading 別讓載入速度拖垮你!
下一篇
[Day 10] Angular 2 動畫 (ANIMATIONS)
系列文
Angular 2 之 30 天邁向神乎其技之路31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
Rach
iT邦新手 4 級 ‧ 2017-02-22 12:04:39

是說在以前angular1的環境底下routing真的寫得不好,所以紛紛轉去ui-router,很推薦ui-router-ng2這個套件做routing,全部state更棒!

我要留言

立即登入留言