如何在 Angular 建立 Route ?
傳統以後端為主的 MVC 寫法,route 會寫在後端;前後端分離的 SPA 寫法,前後端有各自的 route,前端的 route 負責切換 component,而後端的 route 則負責 API。
Version
macOS High Sierra 10.13.3
Node.js 8.9.4
Angular CLI 1.6.7
Angular 5.2.4
建立 Route
建立專案時一併建立 Route
1 | $ ng new MyProject --routing |
新建專案時,加上 --routing
參數。
- Angular CLI 會替我們在
src/app
目錄下新增app-routing.module.ts
檔案 - class 名稱為
AppRoutingModule
routes
陣列即位自訂 route 之處
第 7 行
1 | imports: [RouterModule.forRoot(routes)], |
一般來說,imports
要的都是單純 module,如 BrowserModule
,但這裡用的卻是 RouterModule.forRoot()
。
forRoot()
為RouterModule
的 factory method,為static
, 傳入routes
後,回傳給AppModule
所使用的RouterModule
forChild()
亦為RouterModule
的 factory method,為static
,傳入routes
後,回傳其他 module 所使用的RouterModule
之所以要特別用
forRoot()
與forChild()
,因為當AppModule
與其他 module 都 importRouterModule
時,由於其他 module 都有自己的 DI injector,會屏蔽AppModule
的Router
,有就是說Router
將不再整個 app 共用,而是各 module 有自己的Router
,因此RouterModule
特別不提供 provider,而是改由forRoot()
與forChild()
提供,如此整個 app 將只會有一份Router
- Angular CLI 還替我們修改了
app.module.ts
- 自動將
AppRoutingModule
import 進來
理論上
app.module.ts
與app-routing.module.ts
可以合一,但因為app.module.ts
有他原本的職責,如declarations
、imports
、providers
與bootstrap
,且簡單的 app 也可能也沒使用 route,因此特別將 route 部分特別獨立為app-routing.module.ts
,再 import 進app.module.ts
即可
建立專案後事後加上 Route
假如一開始建立專案時沒加上 --routing
,也可事後再建立 route。
Angular CLI 並沒有提供單獨建立 route 的指令,只能在建立 module 時,順便加上
--routing
參數建立 route
將 app.module.ts 暫時改名
- 將
app.module.ts
暫時改名為app.module.ts.bak
因為我們即將重建
app.module.ts
,所以先將目前的app.module.ts
改名避開
重新建立有 Route 的 AppModule
1 | ~/MyProject $ ng g m App --flat --routing |
m
: module 的縮寫
--flat
: 不要將 AppRouting
建立在目前目錄下,而是建立在 src/app
目錄下
--routing
: 一併建立 AppRoutingModule
- 在專案目錄下執行
ng g m App --flat —routing
- Angular CLI 會替我們建立
app.module.ts
與app-routing.module.ts
兩個檔案 - 在
AppModule
中,會自動幫我們 importAppRoutingModule
刪除 app.module.ts
Angular CLI 剛剛幫我們建立了全新的 app.module.ts
,手動將此檔刪除
因為我們目的是要 Angular CLI 幫我們建立
app-routing.module.ts
,app.module.ts
沒有利用價值需刪除
將 app.module.ts.bak 改為 app.module.ts
- 將
app.module.ts
刪除,再將app.module.ts.bak
重新命名為app.module.ts
app.module.ts.bak
才是我們原本的app.module.ts
修改 AppModule
- 選擇
app.module.ts
- 在
imports
加上剛剛建立的AppRoutingModule
修改 AppRoutingModule
- 選擇
app-routing.module.ts
- 將
forChild()
改成forRoot()
如此無論是一開始建立專案就加上
--routing
參數,或者先建立專案,事後再補建立 route,目前AppModule
都有相同的AppRoutingModule
設定 Route
建立 Login 與 Post Component
使用一般建立 component 的方式建立 LoginComponent
與 PostComponent
(略)
設定 routes
app-routing.module.ts
1 | import { NgModule, Component } from '@angular/core'; |
第 6 行
1 | const routes: Routes = [ |
Routes
為 Angular 定義的 Route
陣列,用來設定 user 自己的 route 定義。
第 7 行
1 | { path: 'login', component: LoginComponent }, |
path
: 設定 route 路徑component
: 當符合path
定義時,該顯示的 component
當 URI 為 login
時,顯示 LoginComponent
第 8 行
1 | { path: 'post', component: PostComponent }, |
當 URI 為 post
時,顯示 PostComponent
第 9 行
1 | { path: '', redirectTo: '', pathMatch: 'full' }, |
redirectTo
: redirect 到其他 URI 路徑pathMatch
: 與path
的匹配方式
當 URI 為 空字串
,redirect 到 ''
,且必須完全符合 path
定義
使用 router-outlet 與 routerLink
app.component.html
1 | Welcome to {{ title }}! |
第 6 行
1 | <router-outlet></router-outlet> |
當在 AppRoutingModule
的 routes
設定 component
時,會顯示在哪呢 ? 就是顯示在 HTML template 的 <router-outlet></router-outlet>
內。
第 2 行
1 | <a routerLink="login">Login</a> |
原本的 <a>
會使用 href
,但這會導致 Angular 使用後端的 route,也就是整個網頁會重新載入;若使用 routerLink
,則 Angular 會使用前端的 route,也就是將 <router-outlet></router-outlet>
換成其他 component,使用者體驗較好。
Conclusion
- Angular 也有自己的 route,傳統頁面跳轉的 route 必須改設定在 Angular
Sample Code
完整的範例可以在 GitHub 上找到