[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.tsimport { 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'":用屬性綁定同步高亮狀態。
filteredgetter 讓模板很乾淨;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)] + 管線/過濾邏輯)