[attr.*]
、[class.*]
)事件綁定:在模板上寫 (事件名)="TS方法()"
<button (click)="doSomething()">點我</button>
當按鈕被點擊,Angular 會呼叫元件類別(.ts)的 doSomething()
。
屬性 / 類別綁定:用中括號把 HTML 屬性綁到變數
<a [href]="linkUrl">連結</a>
<button [class.active]="isActive">按鈕</button>
<div [attr.aria-expanded]="isOpen">...</div>
結構指令(回顧):ngIf
/ ngFor
控制 DOM 是否存在與如何重複渲染。
about.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-about',
templateUrl: './about.component.html',
styleUrls: ['./about.component.scss']
})
export class AboutComponent {
isMoreOpen = false; // 控制展開/收起
toggleMore() {
this.isMoreOpen = !this.isMoreOpen;
}
}
about.component.html
把原先 hidden
與原生 JS 移除,改用 *ngIf
與屬性綁定:
<section id="about" class="container section" aria-labelledby="about-title">
<h2 id="about-title">關於我</h2>
<p>
我是一名前端工程師,喜歡理解使用者需求並把它落地成產品。近期專注於
Angular、TypeScript、前端架構與效能最佳化。
</p>
<blockquote class="quote">「持續學習,讓自己比昨天更強。」</blockquote>
<!-- 只有在 isMoreOpen 為 true 時才渲染 -->
<p *ngIf="isMoreOpen" id="more-info">
曾參與金融科技與電商專案,也投入設計系統與可存取性。閒暇時間喜歡健身、魔術與寫作分享。
</p>
<!-- 事件綁定:點擊時呼叫 toggleMore() -->
<buttonclass="btn small"
type="button"
(click)="toggleMore()"
[attr.aria-expanded]="isMoreOpen"
[attr.aria-controls]="'more-info'">
{{ isMoreOpen ? '收起介紹' : '更多介紹' }}
</button>
</section>
說明:
ngIf="isMoreOpen"
讓段落在狀態為 true 時才存在於 DOM。aria-expanded
/aria-controls
由狀態同步,對可存取性更友善。- 按鈕文字用插值切換(
{{ ... ? '收起' : '更多' }}
)。
aria-selected="true"
、CSS 的 class 切換)skills.component.ts
沿用 Day 9 的資料,加入「目前分類」與「過濾後清單」的 getter。
import { Component } from '@angular/core';
type Category = 'all' | 'frontend' | 'backend' | 'tools';
interface Skill {
name: string;
category: Exclude<Category, 'all'>; // skill 本身不會是 all
}
@Component({
selector: 'app-skills',
templateUrl: './skills.component.html',
styleUrls: ['./skills.component.scss']
})
export class SkillsComponent {
current: Category = 'all';
skills: Skill[] = [
{ name: 'HTML / CSS / SCSS', category: 'frontend' },
{ name: 'TypeScript', category: 'frontend' },
{ name: 'Angular / React / Vue', category: 'frontend' },
{ name: 'Node.js / Express', category: 'backend' },
{ name: 'Git / GitHub / Docker', category: 'tools' },
{ name: 'Vite / Webpack', category: 'tools' }
];
setFilter(cat: Category) {
this.current = cat;
}
// 由目前分類產生要顯示的清單(模板可直接用)
get filtered(): Skill[] {
if (this.current === 'all') return this.skills;
return this.skills.filter(s => s.category === this.current);
}
// ngFor trackBy:提升效能、避免重繪
trackByName(_i: number, s: Skill) { return s.name; }
}
skills.component.html
用 (click)
+ [attr.aria-selected]
切換狀態,列表用 *ngFor
渲染 filtered
。
<section id="skills" class="container section" aria-labelledby="skills-title">
<div class="section-header">
<h2 id="skills-title">技能 Skillset</h2>
<!-- 分類按鈕列 -->
<div role="tablist" aria-label="技能分類" class="filters">
<buttonrole="tab"
class="chip"
(click)="setFilter('all')"
[attr.aria-selected]="current === 'all'">
全部
</button>
<buttonrole="tab"
class="chip"
(click)="setFilter('frontend')"
[attr.aria-selected]="current === 'frontend'">
前端
</button>
<buttonrole="tab"
class="chip"
(click)="setFilter('backend')"
[attr.aria-selected]="current === 'backend'">
後端
</button>
<buttonrole="tab"
class="chip"
(click)="setFilter('tools')"
[attr.aria-selected]="current === 'tools'">
工具
</button>
</div>
</div>
<!-- 清單:用 filtered 取代全部 skills -->
<ul class="skill-grid">
<li *ngFor="let s of filtered; trackBy: trackByName">
{{ s.name }}
</li>
</ul>
</section>
說明:
(click)="setFilter('frontend')"
:事件綁定,點即切換分類。[attr.aria-selected]="current === 'frontend'"
:用屬性綁定同步高亮狀態。filtered
getter 讓模板很乾淨;trackBy
減少重繪。
(click)
+ ngIf
+ 屬性綁定),移除原生 JS 依賴。.ts
管理,維護成本更低。hidden
當邏輯
<p hidden>...</p>
然後用 JS 改 hidden
ngIf
/ [hidden]
:建議 ngIf
,元件銷毀/建立更乾淨(click)="toggleMoree()"
→ console 報 undefined(click)="setFilter('tools')"
ngFor="let s of skills.filter(...)"
每次檢測都跑運算.ts
變成 getter
或預先產生的陣列(如 filtered
)<button class="chip active">
然後用 JS 切 class[class.active]="condition"
或 [attr.aria-selected]="condition"
,資料驅動視覺ngFor="let item of list"
ngFor="let item of list; trackBy: trackById"
回傳穩定識別值明天我們把 Angular 的 雙向綁定 (Two-way binding) 帶進來,做兩個進階改善:
[(ngModel)]
+ 管線/過濾邏輯)