0%

Angular 筆記 - 使用 ngClass 動態改變點擊狀態

demo

本篇記錄前台網站很常出現的點擊標籤切換圖片功能,而使用動態切換 CSS,在點擊標籤時產生對應的資料。

首先有一組標籤資料,有標籤名稱、狀態、圖片。

data

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
tabList = [
{
name: "tab01",
active: true,
imgPath: "https://picsum.photos/400/400?pepple=10",
},
{
name: "tab02",
active: false,
imgPath: "https://picsum.photos/400/400?pepple=20",
},
{
name: "tab03",
active: false,
imgPath: "https://picsum.photos/400/400?pepple=30",
},
{
name: "tab04",
active: false,
imgPath: "https://picsum.photos/400/400?pepple=30",
},
{
name: "tab05",
active: false,
imgPath: "https://picsum.photos/400/400?pepple=30",
},
];

Layout

先把基礎的 template 跟 CSS 以及資料先串接好,

template

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<h1>使用 ngClass 動態改變點擊狀態</h1>
<div class="container">
<ul>
<ng-container *ngFor="let item of tabList">
<li>
<a href="#">{{ item.name }}</a>
</li>
</ng-container>
</ul>
</div>

<ng-container *ngFor="let item of tabList">
<img [src]="item.imgPath" />
</ng-container>

CSS

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
35
36
37
38
39
40
41
42
43
44
45
46
h1 {
text-align: center;
padding: 2rem 0;
font-size: 24px;
font-weight: bold;
color: #009688;
}

.container {
display: flex;
margin: 0 auto;
}

ul {
display: flex;
margin: 0 auto 2rem auto;
}

li {
list-style: none;
}
a {
padding: 1rem 2rem;
color: #009688;
border-bottom: 3px solid transparent;
text-decoration: none;
}
a:hover,
a.active {
background-color: #eee;
transition: all 0.5s ease-in-out;
cursor: pointer;
}

a:hover {
border-bottom: 3px solid #eee;
}

a.active {
border-bottom: 3px solid #009688;
}

img {
display: flex;
margin: 0 auto;
}

完成後,可以看到頁面有標籤,有圖片,跟預期的相同。

layout

加入 ngClass 與點擊事件

在 Angular 看到要動態產生 CSS 的狀態,就要想到 ngClass,

template

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<h1>使用 ngClass 動態改變點擊狀態</h1>
<div class="container">
<ul>
<ng-container *ngFor="let item of tabList">
<li>
<a
href="#"
[ngClass]="{ active: item.active }"
(click)="tabClick(item.name)"
>
{{ item.name }}</a
>
</li>
</ng-container>
</ul>
</div>

<ng-container *ngFor="let item of tabList">
<img [src]="item.imgPath" *ngIf="item.active" />
</ng-container>

TypeScript

1
2
3
4
5
6
7
8
9
tabClick(name: string) {
this.tabList.find((item) => {
if (name === item.name) {
item.active = true;
} else {
item.active = false;
}
});
}

這樣就完成這次的功能了,但上面這個邏輯還有優化的空間!

ngClass 與邏輯優化

後來經資深工程師的建議,他表示如果像是樣式 active 是固定的,正確的 ngClass 用法應該是改成下方這樣,

ngClass 指令修改

因目前 active 是固定不會變動的樣式,可改寫成 class.active,表示這個功能的樣式在 item.active 這個值是 true 的時候,active 就會動態產生。

template

1
2
3
4
5
6
7
<a
href="javascript:void(0)"
[class.active]="item.active"
(click)="tabClick(item.name)"
>
{{ item.name }}</a
>

邏輯修改

原本的邏輯是,點擊事件傳進來的參數是頁籤的名稱,去跟資料裡面的頁籤名稱比對,若找到第一筆相符,該資料的 active 的值就是 true,透過資深工程師指點,因為 if(name === item.name) 的結果也會是 true,故可以把此結果當作是值,讓原本的 item.active 直接等於判斷結果,讓原本五行的程式碼,瞬間一行解決!

Typescript

1
2
3
4
5
tabClick(name: string) {
this.tabList.find((item) => {
item.active = name === item.name;
});
}

小結

此功能是相當簡單又很實用的情境,很多地方都會用到,特別是在優化程式碼的思維更是值得紀錄!所以先求有,再求好!如果公司內部有資深工程是願意 code review 的時候,更是要加倍把握喔!

範例程式碼:https://stackblitz.com/edit/angular-ivy-hffsyu?file=src/app/app.component.ts