iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 21
4
Modern Web

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

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

  • 分享至 

  • xImage
  •  

「原來 Angular 的路由是這樣設定的,比我想像中簡單耶!」Wayne 做完練習之後正玩得不亦樂乎。

「是滿簡單的,不過目前只有第一層而已。在實務上應用時一定會是巢狀的。」我吃了一口最愛的巧克力蛋糕後淡淡地說道。

「對耶!那你快說說巢狀路由要怎麼用?!」Wayne 好像發現新大陸一樣地忽然抓住我的手臂。

「好好好,你不要那麼激動。其實...」


相信大家一定或多或少用過各種大大小小的系統,而且一定會有遇過某些網站的選單特別多層的 (尤其是購物網站) 。那像這麼多層的路由要怎麼設定呢?

其實不難,只要小小地練習一下,把概念弄懂就可以一法通、萬法通了。

還記得我們之前的路由設定嗎?我們來小小地調整一下。

先新建一個 LoginComponent ,大部分的網站或系統一定會有這一頁:

ng generate component login

然後把 LoginComponent 的路由加入我們之前的設定裡:

{
  path: 'login',
  component: LoginComponent
}

然後調整一下畫面,讓我們可以直接在畫面上切換頁面。

首先先在 login.component.html 做個登入的按鈕:

<button routerLink="/home">登入</button>

咦? routerLink 也可以用在除了 <a></a> 之外的元素噢?

沒錯!不知道有沒有人發現,其實 routerLink 是 Angular 的路由機制實作的 Directive,而且還實作了兩個。這個兩個分別是給 <a></a> 用的 RouterLinkWithHref 以及給其他非 <a></a> 元素用的 RouterLink

為什麼我會知道呢?因為看原始碼就知道啦!

在 RouterLinkWithHref 的原始碼裡,你會看到它的 selectora[routerLink] ,意思是只要在 <a></a> 加上 routerLink 的屬性名稱都會觸發這個 Directive 。

而在 RouterLink 的原始碼裡,它的 selector 則是 :not(a)[routerLink] ,意思是只不要是 <a></a> 且有加上 routerLink 的屬性名稱都會觸發這個 Directive 。

不知道 :not() 的邦友可以參考 MDN 的文件 說明

不過通常不會直接在登入按鈕加 routerLink 啦,畢竟一般在登入的時候會一些事情要做,上述只是方便 Demo 以及讓大家之後也可以在非 <a></a> 元素上使用 routerLink 而已。

接著再到 app.component.html 裡加上 logout 的連結:

<li>
  <a
    routerLink="/login"
    routerLinkActive="active"
  >
    Logout
  </a>
</li>

然後畫面大概就會變成這樣:

Imgur

等等!這不是我們要的效果阿!!這樣只是單純地切換來切換去而已阿!!

我們想要的結構應該要像是這樣:

Imgur

好,所以看來我們缺一個 LayoutComponent ,趕快再來新增一下:

ng generate component layout

這個 Component 主要是用來擺放大致上都會共用的 Template ,因為通常只有登入頁的樣式會跟內頁的樣式不太一樣,而其他內頁通常都會長得很像。

所以我們先把 app.component.html 裡的 HTML 都剪下貼到 layout.component.html 裡,然後再在 app.component.html 加一個路由插座 <router-outlet></router-outlet>

記得也要把 app.component.css 裡的樣式剪下來貼到 layout.component.css 裡噢!

然後再來設定 LayoutComponent 的路由:

{
  path: '',
  component: LayoutComponent,
  children: [
    {
      path: 'home',
      component: HomeComponent
    },
    {
      path: 'about',
      component: AboutComponent
    }
  ]
}

有發現到多了一個 children 的屬性嗎?!

沒錯,這裡面放的就是在 LayoutComponent 裡的子層路由,只要路由有設定 children 的路由,再加上在 Template 裡有放 <router-outlet></router-outlet> 的話,Angular 的路由機制就會自動幫你向下找。

加完之後我們來看看效果:

Imgur

看起來運作良好,也有達到巢狀的目的。

不過目前的設定有一個隱憂,會穿幫。

怎麼說呢?我們直接來看怎麼個穿幫法:

Imgur

有發現嗎?當使用者直接連到像是 https://ithelp.ithome.com.tw/ 這樣的 URL 的時候,就只會顯示 LayoutComponent 的部份,子層的 Component 都不會顯示,因為 '' 這個路徑在子層裡面沒有設定。

為防止這樣的情況,目前最簡單的方式是在 children 裡再加上一個轉向路由:

{
  path: '',
  redirectTo: 'home',
  pathMatch: 'full'
}

如此一來, Angular 的路由機制在讀到 '' 的路由時,除了顯示 LayoutComponent 外,也會找到有這個轉向路由,然後就會把路徑轉到 HomeComponent 那邊了。

所以最終,如果我們用 Augury 的 Router Tree 看的話,應該會像是下圖這樣:

Imgur

如果用 Component Tree 看的話,應該會像是這樣:

Imgur

好的,今天就分享到這邊,我們明天見囉!


上一篇
[Angular 深入淺出三十天] Day 19 - 路由(二)
下一篇
[Angular 深入淺出三十天] Day 21 - 路由(四)
系列文
Angular 深入淺出三十天33
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

2 則留言

1
obelisk0114
iT邦新手 5 級 ‧ 2019-11-06 19:53:45
{
  path: '',
  component: LayoutComponent,
  children: [
    {
      path: 'home',
      component: HomeComponent
    },
    {
      path: 'about',
      component: AboutComponent
    }
  ]
}

和不設成子路由, 也就是

{
  path: 'home',
  component: HomeComponent
},
{
  path: 'about',
  component: AboutComponent
},
{
  path: '',
  redirectTo: 'home',
  pathMatch: 'full'
}

差別在哪, 看起來只有把共有的清單部分塞到 LayoutComponent ? 子路由有何優點 ?

Leo iT邦新手 3 級 ‧ 2019-11-06 21:36:04 檢舉

Hi obelisk0114,

  1. 可讀性高的 url ,如: /articles/10207918
  2. 延遲載入。
  3. 減少撰寫重複的程式碼。
  4. 預處理層。

不過一切都是相對於 需求 而言。

如果沒需求,那它就派不上用場。

0
hoanplpyy
iT邦新手 5 級 ‧ 2020-03-22 23:34:12

您好
您在Angular Taiwan youtube頻道中
有一部關於router的教學影片,裡面有提到在簡單的網站中
使用這樣的結構,還可以
{
path: '',
component: LayoutComponent,
children: [
{
path: 'home',
component: HomeComponent
},
{
path: 'about',
component: AboutComponent
}
]
}

但如果在比較複雜的網站,會比較難維護
想要問的是,如果是簡單的網站架構
除了您提到的上述寫法外,還有其他的寫法架構嗎?

Leo iT邦新手 3 級 ‧ 2020-03-24 10:36:41 檢舉

Hi hoanplpyy,

這就看所謂的簡單究竟有多簡單了XDD

不過一般來說,路由設定大致上只有兩種設定方式: Lazy Loading & no Lazy Loading 而已

我要留言

立即登入留言