0%

Angular 筆記 - 實作一個側欄選單與 SPA 頁面

angular

本次練習主題

  • 可收合的側欄選單。
  • 建立 service 共享元件功能。
  • 元件與畫面的分類。
  • 路由與子路由的 SPA 應用。

頁面分類練習

這次練習的過程中釐清了一個觀念就是元件與畫面的分離,別於之前所見即所得的寫法,現在要拆成元件與畫面分離,什麼意思? 前輩簡單教我一個記憶法:

要給使用者看到的稱作畫面,不需要看到的稱為元件。

所以先看一下資料夾內容:

folder

可看到資料夾分成 componentpage,下方一堆 app 開頭的是這支程式的母元件與路由,最下面的 index.html 是整個網頁的入口。

重點在元件與頁面這兩個資料夾

先看一下這次練習的畫面:

index

看起來相當簡單的畫面,目前預設為 Home 的內容,當我選擇 System 標籤,下方會出現兩個選項,點擊該選項後會跑出相對應的內容。

Home

home

System/User

user

System/Group

group

點擊選單右上角的標籤也會進行收合,

close

元件資料夾

下方為元件資料夾的內容,這邊分類的內容就是 aside 的惻欄部分,

component

因為這兩個部分只有單純元件顯示,不是一直改變的內容,所以區分成在元件,而在元件部分又再將上方的 LOGO 與下方的選單拆成兩個元件,也就是 aside 主元件跟 aside-nav 子元件。

建立 service 共用功能

Angular 筆記 - Service 服務元件的基本認識有紀錄如何建立服務元件,而在這邊的服務元件中寫入點擊事件跟判斷是否收合選單,因為兩個介面都使用類似的邏輯,所以就寫在同一個服務元件內。

aside-nav HTML

可看見有事件繫結與屬性繫結的寫法,概念有點像寫 jQuery 在 CSS 中給予對應的 className,然後在用程式邏輯判斷增加 className 後的效果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<ul class="nav">
<li class="btn">
<button class="btn">
<a routerLink="/home/home-text">Home</a>
</button>
</li>
<li class="btn">
<button type="button" class="btn" (click)="featureSvc.toggleList()">
System
</button>
<ul class="systemList" [class.show]="featureSvc.showList()">
<li>
<button class="btnUser">
<a routerLink="/system/system-user" routerLinkActive="active"
>User
</a>
</button>
</li>
<li>
<button class="btnGroup">
<a routerLink="/system/system-group" routerLinkActive="active">
Group</a
>
</button>
</li>
</ul>
</li>
</ul>

service 服務元件

service 宣告變數不用使用 let 或 const,也可以建立。

在 vue 的 data 物件中宣告的變數概念相同。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
export class FeatureService {
close = false; // nav 是否關閉
show = false; // 是否出現選單
constructor() {}

asideToggle() {
return this.close; //回傳點擊後布林值
}

asideSwitch() {
this.close = !this.close; //側欄選單開關
}

showList() {
return this.show; //回傳 nav 選單點擊後的布林值
}

toggleList() {
this.show = !this.show; //nav 選單開關
}
}

這樣就完成了收合選單與項目清單開闔的功能。

路由與子路由呈現 SPA

再來也是這次練習的重頭戲之一,點擊選項讓右邊的畫面呈現對應的內容。

先來看一下路由架構,主要分成以下三大類:

  1. login 路由。
  2. index 路由,沒有寫 path 的原因是預設為起始畫面。
  3. 404 not found 萬用路由
  4. 不管怎麼樣都會回到 home 頁面的萬用路由。

路由的順序是從上讀到下,若找到對應的路徑就會將內容渲染於網頁上。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
const routes: Routes = [
{ path: "login", component: LoginComponent },
{
path: "",
component: IndexComponent,
children: [
{
path: "home",
component: HomeComponent,
children: [
{
path: "home-text",
component: HomeTextComponent,
},
{ path: "**", redirectTo: "home-text", pathMatch: "full" },
],
},
{
path: "system",
component: SystemComponent,
children: [
{
path: "system-user",
component: SystemUserComponent,
},
{ path: "system-group", component: SystemGroupComponent },
],
},
{ path: "**", redirectTo: "login", pathMatch: "full" },
],
},
{ path: "**", component: PageNotFoundComponent },
{ path: "**", redirectTo: "login", pathMatch: "full" },
];

最複雜的串路由來了

先來看一下頁面資料夾的架構,

page

就是將父與子層的頁面做歸納與相依整理,content 資料夾就是整個右側內容的主資料夾,其中會更換頁面的就是 homecontent-main 資料夾,但 content-main 其實都沒有寫任何東西。

HOME 頁面

Home 頁面又拆了 home-text 的元件,當中就是 component 的串接而已,也就是把 <home-text> 的內容注入在 home 的 html 中。

System

因為此標籤下面有兩個選項要呈現對應的內容,所以這邊為路由的接口,所以要放 <router-outlet> 標籤。

System-User 與 System-Group

就分別顯示預設的文字。

index 主頁面

最重要的就是這一頁了,因為更換內容是在 index 裡面,所以 app-content-main 被替換成 <router-outlet> 標籤,做為入口,其它因為不會更動,就只要元件串接就可以。。

1
2
3
4
5
6
7
8
<div class="index">
<app-aside></app-aside>
<div class="content">
<app-content-header></app-content-header>
<router-outlet></router-outlet>
<app-content-footer></app-content-footer>
</div>
</div>

結語

這次練習學習到路由要想著哪一個是頁面進入的接口,並父與子層的關係先建構好,路由也建構完成,彼此的相依順序要釐清,這樣在寫 SPA 與元件拆分才不會搞混,目前架構還沒有寫得非常好,就記錄本次練習做為參考。