iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 22
1
Modern Web

Angular 深入淺出三十天系列 第 22

[Angular 深入淺出三十天] Day 21 - 路由(四)

到目前為止,我們都是只有用 Component 來設定我們的路由。但在實際應用上,通常我們會將相關的功能包裝成一個一個的 NgModule ,而每個 NgModule,也其實都可以有自己的 RoutingModule。

舉例來說,我們先產生一個含有路由的 NgModule:

ng generate module feature --routing

並產生相對應的 Component:

ng generate component feature

接著設定路由:

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

import { FeatureComponent } from './feature.component';

const routes: Routes = [
  {
    path: 'feature',
    component: FeatureComponent
  }
];

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

有發現這邊跟 AppRoutingModule 有個地方不太一樣嗎?

在 AppRoutingModule 的裝飾器裡, RouterModule 是使用 forRoot 的函式:

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

但在 FeatuerRouting 裡, RouterModule 卻是使用 forChild 的函式。

這是一個滿重要的區別,整個系統只有 AppRoutingModule 才會使用 forRoot ,其他的子路由模組都是使用 forChild

不過如果都是用 Angular CLI 來產生元件的話,倒是不用擔心這個。

接著我們先將 FeatureModule 引入到 AppModule 裡,並將其放在 AppRoutingModule 的上面,像是這樣:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

// Routing Module
import { AppRoutingModule } from './app-routing.module';

// Module
import { FeatureModule } from './feature/feature.module';

// Component
import { AppComponent } from './app.component';
import { HomeComponent } from './home/home.component';
import { AboutComponent } from './about/about.component';
import { LoginComponent } from './login/login.component';
import { LayoutComponent } from './layout/layout.component';

@NgModule({
  declarations: [
    AppComponent,
    HomeComponent,
    AboutComponent,
    LoginComponent,
    LayoutComponent
  ],
  imports: [
    BrowserModule,
    FeatureModule, // 放在這裡
    AppRoutingModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

接著再到瀏覽器上輸入 http://localhost:4200/#/feature 看看,應該就能夠看到 feature works! 的字樣:

Imgur

不過這邊要特別留意的是,我們含有路由設定的子功能模組一定要放在 AppRoutingModule 的上面

為什麼呢?

還記得我在路由(二)的時候有提到過路由在查找的時候是有順序性的嗎?

AppRoutingModule 裡有個萬用路由,如果我們把其他含有路由模組的功能模組擺在它之後的話,那我們永遠都別想進到放在它之後的子功能模組裡了。

不信?那我們來試試看:

imports: [
  BrowserModule,
  AppRoutingModule,
  FeatureModule
]

來看看位置對調之後的結果:

Imgur

你看,怎麼樣都進不去吧。

那為什麼會這樣咧?從資料面來看就知道了。

首先我們先打開 home.component.ts 檔,然後注入一個名為 Router 的 Service:

export class HomeComponent implements OnInit {

  constructor(private router: Router) { }

  ngOnInit() {
  }

}

這個名為 Router Service 是 Angular 的路由機制所提供的,之後會再跟大家介紹它。現在只是需要透過它取得我們目前所設定的路由,看看實際上的資料大概會長怎樣。

然後我們在 ngOnInit 的函式裡加入以下的程式碼:

console.log(this.router.config);

如此便能在控制台裡看到我們印出來的資料:

Imgur

你看!是不是跟我說的一樣?! 含有 feature 路由設定的 FeatureModule 因為在 AppRoutingModule 才引入的關係,導致其路由被放到萬用路由後面。

我們把 FeatureModule 跟 AppRoutingModule 的位置交換回來之後再看一次:

Imgur

交換回來之後就不會被放在萬用路由底下了,這就是為什麼萬用路由要放在 routes 陣列裡最後一個,以及 AppRoutingModule 為什麼要放在 imports 陣列裡最後一個的原因。

有了這樣的概念之後,未來才不會有怎麼設路由卻發現怎麼樣都進不去的問題。

那今天就先到這裡,接下來要介紹的是在實務上更為實用的功能噢!

敬請期待!!


上一篇
[Angular 深入淺出三十天] Day 20 - 路由(三)
下一篇
[Angular 深入淺出三十天] Day 22 - 路由(五)
系列文
Angular 深入淺出三十天33

尚未有邦友留言

立即登入留言