所謂父子元件傳遞資料,就是透過使用 props
和 emits
來完成。而 v-model
只是結合使用 props
和 emits
的語法糖。例如在 input 綁上 v-model
時,背後其實是監聽 input 事件,當 input 事件觸發,就更新你在 v-model
所指定的值。
套用以上原理,假設我要把子元件裏的 input 與父元件的資料實現雙向綁定。做法就是:
v-model="你要更新的值"
。在第二步提到的 props,Vue 3 會使用 modelValue
,Vue 2 則需要我們在子元件建立 model
屬性來完成。
另外,非常建議大家參考這部分的官方文件,它簡單說明了 Vue 2 和 Vue 3的做法。
以下會再詳細解說。
我們可以在 input、textarea、select 這些元素上使用 v-model
,雙向綁定資料和用戶輸入的內容。以 input 為例:
<input v-model="text">
data () {
return {
text: 'v-model 綁定的資料'
}
}
仔細想想,這個寫法背後的原理就是:
text
裏。所以,v-model
其實是由監聽 input 事件,以及綁定與更新數值來實現:
<input :value="text" @input="text = $event.target.value"/>
v-model
可以用在父子元件資料傳遞?神奇的是,以上的寫法也可以應用在父子元件,實現雙向綁定資料。
假設目前有兩個元件,父子關係如下:
App.vue
Child.vue
App.vue(父元件):
data() {
return {
msg: "父層 msg",
};
}
Child.vue (子元件):
<input />
我們想要把父元件的 msg 與 Child
的 input 實現雙向綁定。即是說,只要使用者在 Child
子元件裏的 input 一輸入內容,父元件的 msg
也會隨之而更新。
如果你不知道原來 v-model
可以實現這功能,那麼你最快想到的方法可能就是,使用 props
和 emit
,做法像下面這樣:
App.vue:
<template>
{{ msg }}
<Child :childProps="msg" @input-sth="msg = $event"/>
</template>
<script>
import Child from "./components/Child.vue";
export default {
name: "App",
components: {
Child
},
data() {
return {
msg: "父層 msg",
};
},
};
</script>
Child.vue
<template>
<input type="text" :value="childProps" @input="$emit('input-sth', $event.target.value)">
</template>
<script>
export default {
props: ['childProps']
}
</script>
以上就是直接使用 props
和 emit
的方法來完成。透過觸發 input 事件來更新在父元件的資料。
v-model
雙向綁定父子元件的資料然而,用 v-model
來寫就會更簡潔。但要注意的是,props 必須是 modelValue
,emit 事件的名稱必須是 update:modelValue
。
以下先示範 v-model
的寫法,得出的結果是一樣:
App.vue
<template>
{{ msg }}
<Child v-model="msg"/>
</template>
Child.vue
<template>
<input
type="text"
:value="modelValue"
@input="$emit('update:modelValue', $event.target.value)"
/>
</template>
<script>
export default {
props: ["modelValue"],
};
</script>
先看看 Child 的部分,你會發現這裏做的事,跟再前一個例子所做的事是相同。只不過是改了 props 和 emit 事件的名字。
之後,按以上寫法,這裏的 v-model
:
<Child v-model="msg"/>
等於:
<Child :modelValue="msg" @update:modelValue="msg = $event" />
如果想自定義 props 名稱,不用 modelValue
的話,就直接在 v-model
後面定義:
<Child v-model:customProps="msg" />
https://codesandbox.io/s/vue-3-shi-yong-props-emit-shi-xian-v-model-ekk42?file=/src/App.vue
v-model
的做法在 Vue 2 同樣可以使用 v-model
來完成父子元件的雙向綁定。但在子元件的 data 裏,需要加入 model
屬性來指定 v-model
所綁定的 props。
App(父元件):
<Child v-model="msg" />
data() {
return {
msg: "這是父層 Msg",
};
}
Child (子元件):
<div>
<input
:value="childMsg"
@input="$emit('input', $event.target.value)"
/>
</div>
export default {
model: {
prop: "childMsg",
},
props: {
value: String,
childMsg: {
type: String,
default: "default msg",
},
},
};
Vue 3 只需綁定 modelValue
即可。但在 Vue 2,以上示範了要自行加入 model
屬性來指定父層 v-model
所綁定的 props。
v-model
,Vue 2 還可以用 .sync
和 v-bind
除了以上提到的 v-model
方法,.sync
結合 v-bind
做法也能實現同樣效果。還記得以上提到,v-model
其實只是由觸發事件、綁定與更新組成嗎?而 .sync
就是實現這兩個效果的縮寫。
試試用這語法來實現同樣的效果:
Child(子元件):
<div>
<!-- 官方建議 update:myPropName 這格式的寫法 -->
<input
:value="childMsg"
@input="$emit('update:childMsg', $event.target.value)"
/>
</div>
export default {
props: ["childMsg"],
};
App(父元件):
<Child :childMsg.sync="parentMsg" />
data() {
return {
parentMsg: "這是父層 msg"
};
},
注意,這裏的寫法:
<Child :childMsg.sync="parentMsg" />
即等於:
<Child :childMsg="parentMsg" @update:childMsg="parentMsg = $event" />
但謹記:Vue 3 已移除 .sync
語法,只能在 Vue 2 使用。
https://codesandbox.io/s/vue-2-sync-yong-fa-xp4fk?file=/src/App.vue
v-model
來實現父子元件雙向綁定。modelValue
來指定父元件 v-model
所綁定的 props。相反,Vue 2 裏需要在子元件建立 model
屬性來指定 v-model
要綁定的props
。.sync
和 v-bind
來完成 v-model
所實現的效果。重新認識 Vue.js - 2-2 元件之間的溝通傳遞
Vue Component 也可以用 v-model
Vue.js v-model overview