iT邦幫忙

2025 iThome 鐵人賽

DAY 26
0
Modern Web

Angular 進階實務 30天系列 第 26

Day 26:何時該抽元件?從視覺相似到業務邏輯的判斷法則

  • 分享至 

  • xImage
  •  

👉什麼時候該抽取元件?如何設計一個好的元件?怎樣避免過度工程化?

元件化的核心價值

元件化不僅僅是代碼複用,更是關於關注點分離可測試性可維護性。一個設計良好的元件應該具備:

  • 單一職責:每個元件只負責一個明確的功能
  • 高內聚低耦合:元件內部邏輯緊密相關,對外依賴最小化
  • 可複用性:在不同場景下都能正常工作
  • 易測試性:可以獨立進行單元測試

如何判斷適不適合做成元件

視覺判斷法則

前端開發最直觀的判斷方式就是視覺相似性。當你看到兩個或多個UI區塊具有相同的功能和外觀時,這就是抽取元件的明確信號。

https://ithelp.ithome.com.tw/upload/images/20250908/20162350vZAIoMlnDt.png

// ❌ 重複的代碼片段
// 頁面A
<div class="card">
  <div class="card-header">使用者資訊</div>
  <div class="card-body">
    <span>{{userA.name}}</span>
    <nz-tag [nzColor]="userA.status === 'active' ? 'green' : 'red'">
      {{userA.status}}
    </nz-tag>
  </div>
</div>

// 頁面B
<div class="card">
  <div class="card-header">管理員資訊</div>
  <div class="card-body">
    <span>{{adminUser.name}}</span>
    <nz-tag [nzColor]="adminUser.status === 'active' ? 'green' : 'red'">
      {{adminUser.status}}
    </nz-tag>
  </div>
</div>

表格元件的陷阱

特別將表格拉出來講,是因為表格看起來平易近人,又長得很像,好像可以共用元件一樣,但其實他要達成共用的難度最高,其他樣式幾乎長得像就可以抽出來了,但表格不是。
許多開發者看到相似的表格就想將 th 、 td 的內容做成共用元件,但實際上這往往是個災難:

https://ithelp.ithome.com.tw/upload/images/20250908/20162350IqCaLyb9tF.png

最重要的判斷點是:表格的核心服務對象
只要使用單位不同,甚至只是商品項目(EX不同險種保單)不一樣,每個欄位就會有不同的客製化條件。

第二個判斷點是:一格塞很多不一樣的資料欄位,如果是的話建議不要用。
從上圖可以發現使用者表格的 使用者資訊 需要 頭像+姓名+email 的複合顯示,
訂單表格的 商品資訊 需要 商品清單+數量 的複合顯示,這種複合顯示的資料型態基本上不會一樣,
而他們的狀態、時間可能會使用不同的管道(pipe)來調整資料,
所以會變成在創造一個新的規則但是彈性很低。

// ❌ 看似通用,實則複雜
@Component({
  selector: 'app-generic-table',
  template: `
    <nz-table [nzData]="data">
      <thead>
        <tr>
          <th *ngFor="let col of columns">{{col.title}}</th>
        </tr>
      </thead>
      <tbody>
        <tr *ngFor="let item of data">
          <td *ngFor="let col of columns">
            <!-- 這裡會變得非常複雜 -->
            <div [ngSwitch]="col.type">
              <span *ngSwitchCase="'text'">{{item[col.key]}}</span>
              <nz-tag *ngSwitchCase="'tag'">{{item[col.key]}}</nz-tag>
              <button *ngSwitchCase="'button'" nz-button>操作</button>
              <!-- 更多客製化需求... -->
            </div>
          </td>
        </tr>
      </tbody>
    </nz-table>
  `
})
export class GenericTableComponent {
  @Input() data: any[] = [];
  @Input() columns: TableColumn[] = [];
}

現實情況:表格中的每個儲存格往往需要高度客製化的顯示邏輯,包括:

  • 特殊的數據格式化
  • 條件性的樣式應用
  • 複雜的互動邏輯
  • 動態的按鈕組合

判斷標準

適合做成元件的情況

  1. UI結構高度一致:按鈕、卡片、標籤等基礎元件
  2. 邏輯相對固定:表單控件、彈窗、導航等
  3. 複用頻率高:至少在3個以上的地方使用
  4. 未來變動性低:需求相對穩定的功能模組
  5. 相同業務單位:他們偏好同樣色系、間距、圓角、Padding,所以 UI 組件很適合共用

不適合過早抽取的情況

  1. 業務邏輯差異大:看似相似但內部邏輯截然不同
  2. 需求變動頻繁:還在快速迭代的功能模組
  3. 客製化程度高:每次使用都需要大量特殊處理,當你開始寫到第2個ifelse的特殊規格的時候,就可以開始思考了

代碼行數指標

當單個元件檔案超過500行時,就應該考慮拆分:

// ❌ 過於龐大的元件
@Component({
  selector: 'app-user-management',
  templateUrl: './user-management.component.html', // 300+ 行
  styleUrls: ['./user-management.component.scss']   // 200+ 行
})
export class UserManagementComponent {
  // 500+ 行的邏輯代碼
  // 使用者列表邏輯
  // 使用者編輯邏輯
  // 權限管理邏輯
  // 審核流程邏輯
  // ...
}

// ✅ 拆分後的清晰結構
@Component({
  selector: 'app-user-management',
  template: `
    <app-user-list
      [users]="users"
      (userSelect)="onUserSelect($event)">
    </app-user-list>

    <app-user-editor
      [selectedUser]="selectedUser"
      (userSave)="onUserSave($event)">
    </app-user-editor>

    <app-permission-panel
      [user]="selectedUser"
      (permissionChange)="onPermissionChange($event)">
    </app-permission-panel>
  `
})
export class UserManagementComponent {
  // 只負責協調各子元件的互動
}

小結

元件化的價值在於提升可維護性與複用性,掌握「UI結構是否一致」、「邏輯是否固定」、「複用頻率是否足夠」這幾個判斷點,才能讓元件發揮真正的價值,而不是變成新的負擔。

關鍵判斷法則

✅ 3次以上使用 + UI結構高度一致 = 值得抽取
⚠️ 表格元件需謹慎:服務對象不同或複合顯示需求高 = 建議獨立開發
🚨 500行代碼警戒線:超過此數值就該考慮拆分

當你開始為了讓元件「更通用」而加第二個、第三個特殊判斷時,通常代表這個元件已經開始走歪了。這時候停下來,重新評估一下會比硬撐下去要好。
元件化沒有標準答案,多試幾次就會找到適合自己專案的節奏了。


上一篇
Day 25:Angular Reactive Forms – 動態表單 (Schema-driven Forms)
下一篇
Day27:如何寫出可維護的元件?
系列文
Angular 進階實務 30天27
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言