Posted on Leave a comment

[新手教程-6] 使用Routing來切換頁面

什麼是Routing?

Routing意指路由器,也就是由一個路由器來決定現在要顯示的頁面是什麼
在套用Routing時,會有下列的實踐流程
1. 套用轉址設定(讓伺服器不去真正網址所在的位置去讀取資料,而改由Routing來決定現在要顯示什麼畫面)
2. 由url分析要顯示的狀態是什麼
3. 由狀態去獲得真正要取得那些資訊
4. 從這些資訊組成實體
5. 套用導覽動作,由這個畫面切換至另一個畫面

在Angular裡,最佳做法是將載入和設定Routing放在一個top-level的模組內,並於AppModule內來import所有的路由資訊。
按照慣例,模組AppRoutingModuleapp-routing.module.ts會放在src/app

Angular的Routing 產生的虛擬 URL,並不是真的存在於檔案系統裡,因此需要伺服器能夠支援,否則重新整理時會出現404 not found。

新增AppRoutingModule

透過下列CLI的指令來新增一個Routing

ng generate module app-routing --flat --module=app

--flat 的意思是將產出文件放在src/app裡,而非自己一個資料夾
--module=app 則是告知CLI註冊這個Routing在AppModule的imports裡

新產生的src/app/app-routing.module.ts檔案內容如下:

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';

@NgModule({
  imports: [
    CommonModule
  ],
  declarations: []
})
export class AppRoutingModule { }

一般我們不會在Routing裡宣告元件,因此可以將@NgModule.declarations及CommonModule的宣告刪除
通常我們會使用Routes與RouterModule來實做Routing,修改後的檔案如下:

import { NgModule }             from '@angular/core';
import { RouterModule, Routes } from '@angular/router';

@NgModule({
  exports: [ RouterModule ]
})
export class AppRoutingModule {}

增加Routes

此時我們來設定不同路徑要導向的位置,如下面的程式碼

import { HeroesComponent }      from './heroes/heroes.component';

const routes: Routes = [
  { path: '', redirectTo: '/dashboard', pathMatch: 'full' },
  { path: 'heroes', component: HeroesComponent },
  { path: 'detail/:id', component: HeroDetailComponent }
];

上述程式碼代表在網址為http://localhost/heroes時,會在標籤內顯示HeroesComponent這元件的內容。
另外,也要設定當伺服器剛運行時(http://localhost/),要顯示的模組。

設定完Router的map後,將之設定進RouterModule.forRoot()裡
然後再將這整個Router功能設定為可以被export,之後便可以在app.module裡import這個Router

import { NgModule }             from '@angular/core';
import { RouterModule, Routes } from '@angular/router';

import { DashboardComponent }   from './dashboard/dashboard.component';
import { HeroesComponent }      from './heroes/heroes.component';
import { HeroDetailComponent }  from './hero-detail/hero-detail.component';

const routes: Routes = [
  { path: '', redirectTo: '/dashboard', pathMatch: 'full' },
  { path: 'dashboard', component: DashboardComponent },
  { path: 'detail/:id', component: HeroDetailComponent },
  { path: 'heroes', component: HeroesComponent }
];

@NgModule({
  imports: [ RouterModule.forRoot(routes) ],
  exports: [ RouterModule ]
})
export class AppRoutingModule {}

而detail/:id裡的:id可於HeroDetailComponent裡去取得,來做進一步更詳細的資料顯示
取得方法如下:

ngOnInit(): void {
  this.getHero();
}

getHero(): void {
  const id = +this.route.snapshot.paramMap.get('id');//用route.snapshot.paramMap.get取得Routing時傳入的變數
  this.heroService.getHero(id)
    .subscribe(hero => this.hero = hero);
}

我們可以發現,例子中不同的path為所傳入的參數不同,它們代表不同的意義,可以更多元化的設定Routing的功能。Routes可傳入的參數有下面這些

interface Route {
  path?: string //瀏覽器上方的網址列的字串
  pathMatch?: string //當導航至此網址時要顯示的元件
  matcher?: UrlMatcher //網址列過濾器
  component?: Type<any>
  redirectTo?: string //要轉址到那邊
  outlet?: string
  canActivate?: any[]
  canActivateChild?: any[]
  canDeactivate?: any[]
  canLoad?: any[]
  data?: Data //要傳入元件裡的資料
  resolve?: ResolveData
  children?: Routes
  loadChildren?: LoadChildren
  runGuardsAndResolvers?: RunGuardsAndResolvers
}

在這邊可看一下APP_BASE_HREF的設定方式
如果沒有設定,會跑出錯誤訊息如下:

另一個簡單的方式則是在index.html增加下面這行,也可以解決這個錯誤

<base href="/">

在src/app/app.component.html中增加這個導航功能

<h1>{{title}}</h1>

<router-outlet></router-outlet>

利用routerLink來增加導航用超連結

修改src/app/app.component.html如下:

<h1>{{title}}</h1>


<nav>
  <a routerLink="/heroes">Heroes</a>
</nav>

<router-outlet></router-outlet>

如果要回上一頁則使用

goBack(): void {
  this.location.back();
}

這篇文章的範例檔案可由此觀看: live example / download example

參考資料

Leave a Reply