本文 AI 產出,尚未審核

Vue3 Options API(傳統寫法) – Props 完全指南


簡介

在 Vue3 中,Props 是父層與子層之間傳遞資料的唯一官方管道。即使在使用 Composition API 時,Props 的概念依舊不變;但在 Options API(傳統寫法)下,如何宣告、驗證與使用 Props 仍是每位 Vue 開發者必須熟悉的基礎。正確的 Props 設計不僅能提升元件的可重用性,還能避免不必要的錯誤與效能問題。

本篇文章將從 什麼是 Props如何在 Options API 中定義與使用,到 常見陷阱與最佳實踐,提供完整、實務導向的教學,適合剛踏入 Vue3 的新手以及想鞏固概念的中級開發者。


核心概念

1. 為什麼需要 Props?

  • 單向資料流:父層資料只能由上而下傳遞給子層,子層不應直接改變父層的資料,這樣可以避免資料同步的混亂。
  • 元件解耦:子元件只關心自己的 UI 與行為,透過 Props 接收外部資料,使元件更易於測試與重用。

2. 在 Options API 中宣告 Props

在 Options API 中,Props 透過 props 選項宣告,支援兩種寫法:

寫法 說明
陣列寫法 只列出 prop 名稱,類型與預設值皆為 any
物件寫法 可同時設定類型、預設值、必填、驗證函式等。
// MyButton.vue
export default {
  name: 'MyButton',
  // 陣列寫法
  // props: ['label', 'disabled'],

  // 物件寫法(較常使用)
  props: {
    // 類型驗證 + 必填
    label: {
      type: String,
      required: true
    },
    // 預設值 + 類型驗證
    disabled: {
      type: Boolean,
      default: false
    }
  },
  // 其他 Options...
}

小技巧:若只需要簡單傳值,陣列寫法即可;若想加入驗證或預設值,請使用物件寫法。


3. 預設值與類型驗證

3.1 基本類型

props: {
  count: Number,          // 類型為 Number,預設為 undefined
  title: String,          // 類型為 String
  isActive: Boolean       // 類型為 Boolean
}

3.2 使用 default 提供預設值

注意default 只能是靜態值或返回值的函式(當預設值為物件或陣列時必須使用函式返回,以避免所有實例共享同一個引用)。

props: {
  // 靜態預設值
  size: {
    type: String,
    default: 'medium'   // 若父層未傳入 size,預設為 'medium'
  },
  // 物件預設值(必須使用函式返回)
  config: {
    type: Object,
    default: () => ({
      color: 'blue',
      rounded: true
    })
  }
}

3.3 多型別(Array of Types)

props: {
  // 接受 String 或 Number
  value: {
    type: [String, Number],
    required: true
  }
}

4. 單向資料流與 .sync 修飾符

在 Options API 中,子元件 不應直接改變 傳入的 Props;若需要回傳變更,必須透過自訂事件($emit)告訴父層。

// Child.vue
export default {
  props: {
    modelValue: {
      type: Number,
      required: true
    }
  },
  methods: {
    increase() {
      // 正確做法:emit 事件讓父層自行更新
      this.$emit('update:modelValue', this.modelValue + 1)
    }
  }
}

父層使用 .sync(Vue3 已改為 v-model):

<!-- Parent.vue -->
<Child :modelValue="counter" @update:modelValue="counter = $event" />

提醒.sync 已在 Vue3 中被 v-model 取代,但在 Options API 中仍可看到 .sync 的寫法,建議直接使用 v-model 以保持一致性。


5. 動態 Props 與 v-bind

有時候 Props 需要根據條件或資料變化動態傳入,v-bind(縮寫 :)提供了便利的寫法。

<!-- Parent.vue -->
<template>
  <MyCard
    :title="cardTitle"
    :size="isLarge ? 'large' : 'small'"
    v-bind="extraProps"   <!-- 展開額外的 props 物件 -->
  />
</template>

<script>
export default {
  data() {
    return {
      cardTitle: '歡迎使用 Vue3',
      isLarge: true,
      extraProps: {
        elevation: 3,
        rounded: true
      }
    }
  }
}
</script>

6. 自訂驗證函式

有時候內建的類型驗證不足以滿足需求,這時可以使用 validator 自訂驗證邏輯。

props: {
  email: {
    type: String,
    required: true,
    validator(value) {
      // 簡易的 Email 正則驗證
      return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)
    }
  }
}

若驗證失敗,Vue 會在開發環境的 console 中顯示警告,幫助開發者快速定位問題。


常見陷阱與最佳實踐

陷阱 說明 解決方式
直接改變 Props 在子元件內直接 this.prop = newValue 會觸發 Vue 警告,且破壞單向資料流。 使用 $emitv-model 讓父層更新。
預設值共用參考 物件或陣列預設值直接寫在 default: {},所有實例會共享同一個引用。 使用函式返回 default: () => ({})
忘記 required 若必填的 prop 沒有傳入,會在 console 中出現警告,但 UI 可能因為 undefined 而崩潰。 明確設定 required: true,並在父層確保傳值。
過度使用 .sync .sync 會讓子元件「看起來」能改變 prop,實際上仍是事件機制,容易混淆。 直接使用 v-model(或自訂 modelValue)以保持一致性。
驗證函式過於複雜 validator 內部執行大量計算會影響渲染效能。 只做簡單檢查,複雜驗證放在外部工具或 computed 中處理。

最佳實踐

  1. 盡量使用物件寫法,讓每個 prop 的類型、預設值與驗證都一目了然。
  2. 保持 Props 的不可變性:子元件只讀取,不直接改寫。
  3. 為每個 Prop 加上說明文件(或在 props 物件中加入 JSDoc 註解),提升團隊可讀性。
  4. 使用 v-bind="$attrs" 讓元件自動接受未在 props 中宣告的屬性,提升彈性。
  5. 在大型專案中統一 Prop 命名規則(如全部使用 camelCase),避免因大小寫不一致產生錯誤。

實際應用場景

1. 表單元件的雙向綁定

<!-- FormInput.vue -->
<template>
  <input
    :value="modelValue"
    @input="$emit('update:modelValue', $event.target.value)"
  />
</template>

<script>
export default {
  props: {
    modelValue: {
      type: String,
      default: ''
    }
  }
}
</script>

父層:

<FormInput v-model="username" />

2. 卡片元件的彈性樣式

// Card.vue
export default {
  props: {
    title: String,
    elevation: {
      type: Number,
      default: 1,
      validator: v => v >= 0 && v <= 5
    },
    rounded: {
      type: Boolean,
      default: false
    }
  }
}

使用:

<Card
  title="最新消息"
  :elevation="3"
  rounded
/>

3. 列表渲染的資料來源

// ItemList.vue
export default {
  props: {
    items: {
      type: Array,
      required: true,
      validator: arr => arr.every(i => typeof i.id !== 'undefined')
    }
  }
}

父層:

<ItemList :items="todoList" />

此方式確保傳入的 items 陣列每個元素都有 id,避免在 v-for 中出現 key 錯誤。


總結

  • Props 是 Vue3 Options API 中父子元件溝通的核心機制,必須遵守 單向資料流 原則。
  • 透過 物件寫法 可以同時設定 類型、預設值、必填與自訂驗證,提升元件的魯棒性。
  • 不要在子元件內直接修改 Prop,應使用 $emit(或 v-model)讓父層負責更新。
  • 正確處理 預設值的引用validator 的效能、以及 .sync vs v-model 的差異,能避免常見的開發陷阱。
  • 在實務上,Props 常被用於 表單雙向綁定、彈性樣式設定、以及 資料列表傳遞,只要掌握上述概念,就能寫出可重用、易維護的 Vue3 元件。

希望這篇指南能幫助你在 Vue3 Options API 中更自信地使用 Props,打造高品質的前端應用!祝開發順利 🚀