「原來 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 的原始碼裡,你會看到它的 selector
是 a[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>
然後畫面大概就會變成這樣:
等等!這不是我們要的效果阿!!這樣只是單純地切換來切換去而已阿!!
我們想要的結構應該要像是這樣:
好,所以看來我們缺一個 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 的路由機制就會自動幫你向下找。
加完之後我們來看看效果:
看起來運作良好,也有達到巢狀的目的。
不過目前的設定有一個隱憂,會穿幫。
怎麼說呢?我們直接來看怎麼個穿幫法:
有發現嗎?當使用者直接連到像是 https://ithelp.ithome.com.tw/
這樣的 URL 的時候,就只會顯示 LayoutComponent 的部份,子層的 Component 都不會顯示,因為 ''
這個路徑在子層裡面沒有設定。
為防止這樣的情況,目前最簡單的方式是在 children
裡再加上一個轉向路由:
{
path: '',
redirectTo: 'home',
pathMatch: 'full'
}
如此一來, Angular 的路由機制在讀到 ''
的路由時,除了顯示 LayoutComponent 外,也會找到有這個轉向路由,然後就會把路徑轉到 HomeComponent 那邊了。
所以最終,如果我們用 Augury 的 Router Tree 看的話,應該會像是下圖這樣:
如果用 Component Tree 看的話,應該會像是這樣:
好的,今天就分享到這邊,我們明天見囉!
{
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 ? 子路由有何優點 ?
Hi obelisk0114,
/articles/10207918
。不過一切都是相對於 需求
而言。
如果沒需求,那它就派不上用場。
您好
您在Angular Taiwan youtube頻道中
有一部關於router的教學影片,裡面有提到在簡單的網站中
使用這樣的結構,還可以
{
path: '',
component: LayoutComponent,
children: [
{
path: 'home',
component: HomeComponent
},
{
path: 'about',
component: AboutComponent
}
]
}
但如果在比較複雜的網站,會比較難維護
想要問的是,如果是簡單的網站架構
除了您提到的上述寫法外,還有其他的寫法架構嗎?
Hi hoanplpyy,
這就看所謂的簡單
究竟有多簡單了XDD
不過一般來說,路由設定大致上只有兩種設定方式: Lazy Loading & no Lazy Loading 而已