本文 AI 產出,尚未審核
Vue3 – 元件基礎:元件的定義方式(Options API vs Composition API)
簡介
在 Vue3 中,**元件(Component)**是建立可重用 UI 與行為的核心單位。無論是簡單的按鈕,還是複雜的資料表,都會以元件的形式出現在應用程式裡。掌握元件的定義方式,是從「寫出第一行程式」到「打造大型專案」的關鍵一步。
Vue3 同時提供兩套主流的 API:Options API(傳統寫法)與 Composition API(全新寫法)。Options API 以 data、methods、computed 等選項分門別類,適合剛接觸 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 |
|---|---|---|
| 結構 | data、methods、watch 分散 |
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) | 沒有正確聲明 ref、reactive 的型別,編譯時會失去提示。 |
在 script setup lang="ts" 中使用 ref<number>(0) 等方式明確型別。 |
最佳實踐
- 新專案首選 Composition API:提供更好的邏輯組合與 TypeScript 支援。
- 小型元件或快速原型仍可使用 Options API:語法直觀,上手快。
- 將可重用邏輯抽成 composable,並放在
src/composables/資料夾,保持專案結構清晰。 - 使用
<script setup>,省去冗長的export default,讓檔案更簡潔。 - 保持模板與邏輯分離:僅在
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」的共識,讓程式碼庫保持乾淨且易於演進。祝開發順利!