本篇記錄前台網站很常出現的點擊標籤切換圖片功能,而使用動態切換 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; }
|
完成後,可以看到頁面有標籤,有圖片,跟預期的相同。
加入 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