<input v-model="str" />
// 等同于
<input :value="str" @input="str = $event.target.value" />
通過上面的代碼,我們可以分析得出,也就是說:<font color=red> v-model="str" 是 :value="str" @input="str = $event.target.value" 的縮寫。</font>
解釋:
$event 指代當(dāng)前觸發(fā)的事件對(duì)象。
$event.target 指代當(dāng)前觸發(fā)的事件對(duì)象的dom
$event.target.value 就是當(dāng)前dom的value值
在@input方法中,value => str
在:value中:str => value
如此,形成了一個(gè)閉環(huán),也就是所說的數(shù)據(jù)的雙向綁定。
自定義組件怎么實(shí)現(xiàn)v-model
<my-component v-model="price"></my-component>
我們可以根據(jù)規(guī)則來拆解
<my-component :value="price" @input="price = $event.target.value"></my-component>
那么我們在還原組件的封裝
<template>
<div>
<input type="text" :value="value" @input="$emit('input', $event.target.value)">
</div>
</template>
<script>
export default {
props: {
value: String
}
}
</script>
看到上面的代碼或許你就恍然大悟了,他又回到了,我們之前學(xué)過的 父子組件的來回傳值。
細(xì)心的同學(xué)可能會(huì)發(fā)現(xiàn),我們 props 里面的值是 value 那我能不能隨便定義一個(gè)變量呢?還有 $emit()里面?zhèn)魅氲氖录凳莍nput我能不能也隨便定義一個(gè)事件呢?
當(dāng)我們在一個(gè)自定義組件上使用v-model并不能實(shí)現(xiàn)雙向綁定,因?yàn)樽远ǖ慕M件并沒有默認(rèn)的value和input事件,在使用時(shí),我們需要按照上面那樣顯式的去聲明定義這些東西。這時(shí),model選項(xiàng)就派上用場了,在定義組件的時(shí)候,指定prop的值和監(jiān)聽的事件。
組件的用法是不變的,子組件可以這么寫
<template>
<div>
<input type="text" :value="xxxx" @input="$emit('xxxx', $event.target.value)">
</div>
</template>
<script>
export default {
model:{
prop:'xxxx',
event:'xxxx' // 代表自定義的事件名稱
}
props: {
xxxx: String // 代表自定義的變量名稱
}
}
</script>
這就是vue 的 model 選項(xiàng)的作用。
以上是vue2.0的v-model語法糖講解,vue3.0是怎么用的呢?
其實(shí)vue3的v-model跟vue2的使用區(qū)別不大,只是跟vue2的 <font color=red>sync</font> 修飾符進(jìn)行了合并,所以在vue3中就移除了 <font color=red>sync</font> 修飾符。下面我們看看怎么在 <font color=red>composition api</font>
中怎么寫 <font color=red>v-model</font>
// 自定義一個(gè)TestModel組件
<template>
<div>
<input type="text" :value="modelValue" @input="$emit('update:modelValue', $event.target.value)" />
</div>
</template>
<script>
export default {
props: {
modelValue: {
type: String
}
}
}
</script>
在vue3中默認(rèn)的不在是value 而是modelValue
然后在其他頁面使用
<template>
<h1>vue3中使用v-model {{msg}}</h1>
<testModel v-model="msg"></testModel>
<!-- 等同于下面語法 默認(rèn)傳入一個(gè)modelValue 然后子組件接收這個(gè)modelValue -->
<testModel :modelValue="msg" @update:modelValue="msg = $event"></testModel>
</template>
<script>
import { ref } from 'vue';
import testModel from './TestModel.vue';
export default {
components: {
testModel
},
setup(){
const msg = ref('')
return { msg }
},
}
</script>
有的小伙伴可能有疑問,如果我不想用 modelValue 怎么辦呢?當(dāng)然也可以寫成其他的名字
// 父組件
<template>
<h1>vue3中使用v-model {{msg}}</h1>
<testModel v-model:msg="msg"></testModel>
</template>
子組件接收的props就要改成msg了
// 子組件
<template>
<div>
<input type="text" :value="msg" @input="$emit('update:msg', $event.target.value)" />
</div>
</template>
<script>
export default {
props: {
msg: {
type: String
}
}
}
</script>
當(dāng)然提到雙向綁定,你可能第一時(shí)間就會(huì)想到表單元素,雙向綁定不一定是表單元素,你可以定義各種各樣的組件,比如通過click事件改變父組件的值
// 父組件
<template>
<div>{{count}}</div>
<testModel v-model:count="count"></testModel>
</template>
<script>
export default {
components: {
testModel
},
setup(){
const count = ref(0)
return { count }
}
}
</script>
// 子組件
<template>
<!-- 一定是+1 不是+=1 或者++ 否則vue會(huì)觸發(fā)一個(gè)不讓子組件直接改變props的警告 -->
<div @click="$emit('update:count', count + 1)">click me count + 1!</div>
</template>
<script>
export default {
props: {
count: {
type: Number
}
}
}
</script>