本文 AI 產出,尚未審核

Vue3 – 元件基礎:元件的定義方式(Options API vs Composition API)

簡介

在 Vue3 中,**元件(Component)**是建立可重用 UI 與行為的核心單位。無論是簡單的按鈕,還是複雜的資料表,都會以元件的形式出現在應用程式裡。掌握元件的定義方式,是從「寫出第一行程式」到「打造大型專案」的關鍵一步。

Vue3 同時提供兩套主流的 API:Options API(傳統寫法)與 Composition API(全新寫法)。Options API 以 datamethodscomputed 等選項分門別類,適合剛接觸 Vue 的新手;Composition API 則以 setup 函式為入口,允許把相關邏輯「組合」在一起,提升可讀性與可維護性,特別適合中大型專案。

本篇文章將比較兩種寫法的語法與概念,示範實作範例,並說明在什麼情境下選擇哪一種較為合適。


核心概念

1. Options API 基本結構

// MyButton.vue
<template>
  <button @click="increment">{{ count }}</button>
</template>

<script>
export default {
  // 1. 狀態 (data)
  data() {
    return {
      count: 0
    }
  },

  // 2. 方法 (methods)
  methods: {
    increment() {
      this.count++
    }
  },

  // 3. 計算屬性 (computed)
  computed: {
    // 這裡示範簡單的文字說明
    label() {
      return `已點擊 ${this.count} 次`
    }
  }
}
</script>
  • data:回傳一個物件,裡面的屬性會被 Vue 轉成響應式。
  • methods:放置所有可呼叫的函式,this 會自動指向元件實例。
  • computed:基於響應式依賴自動緩存的屬性,常用於衍生資料。

2. Composition API 基本結構

// MyButton.vue
<template>
  <button @click="increment">{{ count }}</button>
</template>

<script setup>
import { ref, computed } from 'vue'

// 1. 狀態 (ref / reactive)
const count = ref(0)

// 2. 方法 (function)
function increment() {
  count.value++
}

// 3. 計算屬性 (computed)
const label = computed(() => `已點擊 ${count.value} 次`)

// 直接在 <script setup> 中暴露給模板使用
</script>
  • ref / reactive:建立響應式資料。ref 包住原始值,透過 .value 讀寫;reactive 則是整個物件皆為響應式。
  • setup:在元件建立前執行,返回的變數與函式會自動暴露給模板。使用 <script setup> 可省去 export default {} 的寫法,語法更簡潔。
  • computed:與 Options API 相同,只是寫法改為函式形式。

3. 組合式邏輯的抽離(Composable)

// useCounter.js
import { ref, computed } from 'vue'

export function useCounter(initial = 0) {
  const count = ref(initial)

  const increment = () => count.value++
  const decrement = () => count.value--

  const double = computed(() => count.value * 2)

  return { count, increment, decrement, double }
}
// CounterDisplay.vue
<template>
  <div>
    <p>計數:{{ count }}</p>
    <p>雙倍:{{ double }}</p>
    <button @click="increment">+</button>
    <button @click="decrement">-</button>
  </div>
</template>

<script setup>
import { useCounter } from './useCounter.js'

const { count, increment, decrement, double } = useCounter(5)
</script>
  • Composable:把相關的狀態與行為封裝成可重用的函式,讓不同元件共享同一套邏輯。這是 Composition API 的最大優勢。

4. 範例比較:表單驗證

項目 Options API Composition API
結構 datamethodswatch 分散 setup 內統一
重用性 需要 mixins 或高階元件 直接使用 composable
可讀性 小型元件 OK,複雜時易散亂 邏輯聚合,易維護
// Options API 版 – FormValidator.vue
<script>
export default {
  data() {
    return { email: '', error: '' }
  },
  watch: {
    email(val) {
      this.error = /.+@.+\..+/.test(val) ? '' : 'Email 格式錯誤'
    }
  },
  methods: {
    submit() {
      if (!this.error) alert('送出成功')
    }
  }
}
</script>
// Composition API 版 – FormValidator.vue
<script setup>
import { ref, watch } from 'vue'

const email = ref('')
const error = ref('')

watch(email, (val) => {
  error.value = /.+@.+\..+/.test(val) ? '' : 'Email 格式錯誤'
})

function submit() {
  if (!error.value) alert('送出成功')
}
</script>

<template>
  <input v-model="email" placeholder="輸入 Email">
  <p style="color:red">{{ error }}</p>
  <button @click="submit">送出</button>
</template>

常見陷阱與最佳實踐

陷阱 說明 解決方式
this 指向錯誤(Options API) 在普通函式裡 this 可能不是元件實例。 使用箭頭函式或在 methods 中使用 function,確保 this 為 Vue 實例。
忘記 .value(Composition API) ref 內的值必須透過 .value 讀寫,否則不會觸發更新。 建議在 IDE 加入 eslint-plugin-vue 規則,或使用 reactive 包裹物件。
過度抽離(Composable) 把太多不相關的功能放在同一個 composable,會降低可讀性。 遵循單一職責原則,每個 composable 只負責一塊邏輯。
混用兩套 API 在同一個元件內同時使用 Options & Composition,容易產生混亂。 若要混用,盡量將 Composition 置於 setup() 中,僅保留 Options 作為外層包裝;或直接統一使用 <script setup>
缺少型別(TypeScript) 沒有正確聲明 refreactive 的型別,編譯時會失去提示。 script setup lang="ts" 中使用 ref<number>(0) 等方式明確型別。

最佳實踐

  1. 新專案首選 Composition API:提供更好的邏輯組合與 TypeScript 支援。
  2. 小型元件或快速原型仍可使用 Options API:語法直觀,上手快。
  3. 將可重用邏輯抽成 composable,並放在 src/composables/ 資料夾,保持專案結構清晰。
  4. 使用 <script setup>,省去冗長的 export default,讓檔案更簡潔。
  5. 保持模板與邏輯分離:僅在 setup 中處理資料,模板只負責渲染。

實際應用場景

場景 建議使用 為什麼
簡單 UI 元件(按鈕、圖示) Options API 或 <script setup> 需求單一,寫法簡潔,維護成本低。
表單驗證、資料抓取等複雜邏輯 Composition API + composable 可把驗證、API 呼叫、狀態管理分離,重用度高。
大型儀表板(多圖表、即時資料) 完全採用 Composition API,配合 Pinia 組合式寫法與 Pinia 的 store 能夠協同管理全局與局部狀態。
團隊開發、需要統一規範 使用 <script setup> + ESLint + Prettier 統一語法風格,減少衝突,提升碼審效率。
需要支援 TypeScript Composition API(ref<T>()reactive<T>() TypeScript 在 composable 中的型別推斷更完整。

總結

  • Options API:結構化、易上手,適合小型或快速原型開發。
  • Composition API:以 setup 為核心,提供邏輯聚合、可重用的 composable,對中大型專案與 TypeScript 支援更友好。
  • 兩者並非互斥,而是根據需求選擇的工具。掌握兩套 API 的語法與最佳實踐,能讓你在 Vue3 的開發旅程中游刃有餘,從簡單元件到龐大系統,都能寫出可維護、可擴充的程式碼。

實務建議:在新專案中以 Composition API 為主,若遇到極簡元件仍可使用 Options API;在團隊內部建立「何時抽成 composable」的共識,讓程式碼庫保持乾淨且易於演進。祝開發順利!