本文 AI 產出,尚未審核

Vue3 Composition API:computed 的 Getter / Setter 實作與應用


簡介

在 Vue 3 中,computed 不僅是一個只讀的衍生屬性,還可以同時提供 gettersetter,讓你在 UI 與資料之間建立雙向的映射關係。
透過 Composition API 的 computed(() => ...) 形式,我們可以把複雜的資料轉換、驗證、或同步邏輯封裝在同一個可觀測的變數裡,讓組件的 可讀性可維護性 大幅提升。

本篇文章將帶你從概念說明、實作範例,到常見陷阱與最佳實踐,完整掌握 computed getter / setter 的使用方式,並提供幾個在實務開發中常見的應用情境。


核心概念

1. 為什麼需要 setter?

  • 雙向綁定:在使用 <input v-model="fullName"> 時,若 fullName 是一個計算屬性,Vue 會自動呼叫其 setter 來更新底層資料。
  • 資料驗證:在 setter 中加入驗證或格式化邏輯,可避免不合法的值寫入原始資料。
  • 同步多個來源:當一個 UI 元件需要同時影響多個 state 時,setter 可以一次性完成同步,避免多次觸發重繪。

2. computed 的基本語法

import { ref, computed } from 'vue'

const count = ref(0)

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

若要同時提供 getter 與 setter,必須傳入一個 物件,物件裡包含 getset 兩個函式:

const fullName = computed({
  get() {
    // 讀取時的邏輯
  },
  set(value) {
    // 寫入時的邏輯
  }
})

3. Getter / Setter 的執行時機

時機 觸發方式 執行的函式
讀取 computed.value(或在模板中直接使用) getter 被呼叫,回傳衍生值 get()
computed 設定新值(如 v-model setter 被呼叫,接收新值 set(newValue)
依賴的 refreactive 變更 getter 重新計算 get() 再次執行

⚠️ 注意:setter 只會在外部「寫入」時被呼叫,內部自行修改依賴的 ref 不會觸發 setter。

4. 範例一:姓名分拆與合併

import { ref, computed } from 'vue'

export default {
  setup() {
    const firstName = ref('王')
    const lastName = ref('小明')

    // fullName 同時提供 getter 與 setter
    const fullName = computed({
      // 讀取時把姓與名組合成「王 小明」
      get() {
        return `${firstName.value} ${lastName.value}`
      },
      // 寫入時把傳入的字串切割回姓與名
      set(value) {
        const [first, ...rest] = value.split(' ')
        firstName.value = first
        lastName.value = rest.join(' ')
      }
    })

    return { firstName, lastName, fullName }
  }
}

說明:在表單上使用 <input v-model="fullName">,使用者編輯「王 小明」時,setter 會自動把字串拆回 firstNamelastName,實現 雙向綁定

5. 範例二:價格與稅金的雙向計算

import { ref, computed } from 'vue'

export default {
  setup() {
    const price = ref(1000)          // 稅前價格
    const taxRate = ref(0.05)        // 稅率 5%

    // total 包含稅金,既能讀也能寫
    const total = computed({
      get() {
        return price.value * (1 + taxRate.value)
      },
      set(value) {
        // 使用者直接輸入含稅金額,我們反推稅前價格
        price.value = value / (1 + taxRate.value)
      }
    })

    return { price, taxRate, total }
  }
}

說明:當 UI 允許使用者直接輸入「含稅金額」時,setter 會自動把金額轉回「稅前價格」,避免在其他地方重複寫反推邏輯。

6. 範例三:表單欄位的即時驗證

import { ref, computed } from 'vue'

export default {
  setup() {
    const rawAge = ref('')   // 使用者輸入的字串

    const age = computed({
      get() {
        // 只要是合法的正整數就回傳 Number,否則回傳 null
        const n = Number(rawAge.value)
        return Number.isInteger(n) && n > 0 ? n : null
      },
      set(value) {
        // 只接受正整數,其他值直接忽略
        if (Number.isInteger(value) && value > 0) {
          rawAge.value = String(value)
        }
      }
    })

    // 用於 UI 顯示錯誤訊息
    const ageError = computed(() => {
      return rawAge.value !== '' && age.value === null
        ? '年齡必須是正整數'
        : ''
    })

    return { rawAge, age, ageError }
  }
}

說明:透過 setter 的驗證,我們保證 age 永遠是 Numbernull,而 UI 只需要監看 ageError 即可顯示即時錯誤訊息。


常見陷阱與最佳實踐

陷阱 可能的後果 解決方案
在 setter 中直接改寫同一個 computed 造成無限遞迴或 Stack Overflow 永遠 改寫其 依賴的 refreactive,不要在 setter 內部再次賦值給自己。
忘記返回值(getter 沒有 return computed 永遠回傳 undefined,導致 UI 顯示錯誤 確認 get() 函式最後有 return,或使用箭頭函式直接回傳。
在 getter 中執行副作用(如 API 呼叫) 每次依賴變更都會觸發副作用,造成效能與重複請求問題 副作用應放在 watchwatchEffect,保持 getter 純函式
使用 ref 包裝已是 computed 的值 產生不必要的嵌套,讀取時需 .value.value 只在需要時才使用 ref,不要把 computed 再包一層 ref
忘記在模板中使用 .value(Composition API) 顯示空白或錯誤訊息 <script setup> 中直接使用變數,Vue 會自動解包;在普通 setup 返回時,模板仍需 .value

最佳實踐

  1. 保持 getter 純粹:只做計算與回傳,不修改任何 state。
  2. 在 setter 中集中所有寫入邏輯:包括驗證、格式化、同步其他欄位。
  3. 使用 TypeScript 時明確標註型別,例如 computed<string>,可以提前捕捉錯誤。
  4. 對於需要多個依賴的 computed,盡量拆成小的 computed 再組合,提升可讀性與重用性。
  5. 在大型表單或資料同步情境下,搭配 watch 監控 computed 的變化,以執行額外的副作用(如 API 更新)。

實際應用場景

場景 為什麼使用 computed getter/setter
表單欄位聯動(例如「地址」分為縣市與郵遞區號) 使用 getter 合併顯示,setter 解析回各自的 ref,保持 UI 與資料同步。
金額顯示與編輯(含稅 / 未稅) 讓使用者自由切換編輯模式,setter 自動把輸入的金額轉換為內部統一的基礎值。
多語系文字切換 getter 根據當前語系返回對應文字,setter 可在需要時改變語系(如切換語系的 UI 控制)。
即時驗證與格式化(電話號碼、信用卡號) setter 只接受符合格式的值,getter 回傳已格式化的字串,減少 UI 重複處理。
資料視圖層的投影(只顯示部分屬性) 在列表頁只需要顯示 fullName,在編輯頁使用相同 computed 的 setter 直接寫回。

總結

  • computedgetter / setter 為 Vue 3 Composition API 提供了 雙向計算屬性 的能力,是實作 v-model表單同步即時驗證 等需求的關鍵工具。
  • getter 必須保持純粹,只負責計算與回傳;setter 則是集中寫入、驗證與同步的地方。
  • 正確使用可以讓程式碼更簡潔可讀可維護,同時避免不必要的效能問題。
  • 在開發過程中留意常見陷阱(遞迴、在 getter 中副作用)並遵守最佳實踐,能讓你的 Vue 3 專案更穩定、易於擴充。

掌握了 computed getter / setter,你就能在 Vue 3 中以更精緻的方式管理資料與 UI 之間的互動,寫出既直觀強大的應用程式。祝開發順利!