2025-04-01- Vue 的 computed 及 v-modal 的不同

2025-04-01- Vue 的 computed 及 v-modal 的不同

很多人一開始會想:「既然 v-model 是雙向的,那我直接用 computed() 來做 getter / setter 不就好了?」
其實這兩個在父子元件傳值的情境裡,解決的問題不一樣


1️⃣ computed() 用在哪?

computed在元件內部建立「衍生值」或「雙向綁定某個內部狀態」的工具。
它的 getter / setter 可以做雙向邏輯,但這是元件內部的資料流不是父子元件溝通的機制

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<script setup>
import { ref, computed } from 'vue'

const firstName = ref('Lily')
const lastName = ref('Chiou')

const fullName = computed({
get: () => firstName.value + ' ' + lastName.value,
set: (value) => {
const parts = value.split(' ')
firstName.value = parts[0] || ''
lastName.value = parts[1] || ''
}
})
</script>

這裡的 fullName 完全不需要 propsemit,因為它只在元件自己內部用。


2️⃣ v-model 用在哪?

當你需要父子元件雙向傳值時,必須透過:

  • props 接收父元件傳來的值
  • emit 事件回傳給父元件

因為 Vue 的資料流是單向的(父 → 子),
子元件不能直接改父元件的變數,所以才需要 $emit 讓父元件去改。


3️⃣ 為什麼子元件不能直接用 computed() 改父元件的值?

假設子元件直接:

1
2
3
4
const text = computed({
get: () => props.modelValue,
set: (val) => props.modelValue = val // ❌ 不行
})

這樣會報錯:

1
[Vue warn]: Attempting to mutate prop "modelValue"

因為 props 在子元件是唯讀的,Vue 強制禁止直接修改,
所以即使你用 computed,setter 也沒辦法直接改 props
你還是必須用 $emit('update:modelValue', 新值) 告訴父元件去改。


正確結合 computed + v-model 的方式(有些人喜歡這樣寫比較簡潔)

1
2
3
4
5
6
7
8
9
10
11
12
13
<script setup>
const props = defineProps({ modelValue: String })
const emit = defineEmits(['update:modelValue'])

const text = computed({
get: () => props.modelValue,
set: (val) => emit('update:modelValue', val)
})
</script>

<template>
<input v-model="text" />
</template>

這種方式只是讓你在 <template> 裡可以用 v-model="text"
而不用再手動寫 :value@input
但底層還是要靠 emit 回傳,才能讓父元件更新


💡 重點

  • computed元件內部狀態的雙向邏輯工具
  • v-model(props + emit)是父子元件間的雙向資料傳遞機制
  • 在子元件中用 computed 包 props + emit,只是寫法簡化,邏輯沒變