Vue 官網教程上關于 v-model
的講解不是十分的詳細,寫這篇文章的目的就是詳細的剖析一下, 并介紹 Vue 2.2 v-model
改進的地方,然后穿插的再說點 Vue 的小知識。
在 Vue 中,有許多方法和 Angular 相似,這主要是因為 Angular 是 Vue 早期開發的靈感來源。然而,Augular 中存在許多問題,在 Vue 中已經得到解決。
v-model 用在 input 元素上時
v-model
雖然很像使用了雙向數據綁定的 Angular 的 ng-model
,但是 Vue 是單項數據流,v-model
只是語法糖而已:↓
<input v-model="sth" />
<input :value="sth" @input="sth = $event.target.value" />
第一行的代碼其實只是第二行的語法糖,兩行代碼是等價的。
要理解這行代碼,首先你要知道 input
元素本身有個 oninput 事件,這是 HTML5 新增加的,類似 onchange
,每當輸入框內容發生變化,就會觸發 oninput
,把最新的value
賦值給 sth
變量。
如果你不知道 $event 是從哪來的,那你需要點擊它再復習一下文檔。
我們仔細觀察語法糖和原始語法那兩行代碼,可以得出一個結論:
在給 <input /> 元素添加 v-model 屬性時,默認會把 value
作為元素的屬性,把 input
事件作為實時傳遞 value 的觸發事件
(理解上面那句話非常重要,如果沒有理解,務必再把上面的內容多看兩遍,多想想,直到理解為止)
當 v-model 用在組件上時
v-model
不僅僅能在 input
HTML 原生標簽上用,在 vue 組件上也能使用;下面是一個和 Vue 官網教程類似的例子:
父組件 price
的初始值是 100,子組件是一個輸入框;輸入框的值改變時,能實時更新父組件的 price
// 父組件
<template>
<div id="demo">
<currency-input v-model="price"></currentcy-input>
<span>{{price}}</span>
</div>
</template>
<script>
export default {
data() {
return {
price: 100,
}
}
}
</script>
// 子組件 currency-input
<template>
<input
:value="value"
@input="$emit('input', $event.target.value)"
/>
<!--為什么這里把 'input' 作為觸發事件的事件名?`input` 在哪定義的?-->
</template>
<script>
export default {
props: {
value: String, // 為什么這里要定義 value 屬性,父組件貌似沒有給子組件傳遞 value 啊?
}
}
</script>
注釋里列了兩個問題,如果你都知道答案,那么恭喜你真正掌握了 v-model
!
如果你沒明白,那么可以繼續往下看
我們對比下下面兩行代碼
<currency-input v-model="price"></currentcy-input>
<currency-input :value="price" @input="price = $event.target.value"></currency-input>
這兩行代碼實際上沒有任何區別,只不過第一行是第二行的語法糖而已!
現在你知道 value
和 input
從哪來的了吧。與上面總結的類似:
給組件添加 v-model
屬性時,默認會把value
作為組件的屬性,把 input
作為給組件綁定事件時的事件名
v-model 的缺點和解決辦法
v-model 應用到組件上,會有一些體驗不好的場景。因為它默認會把 value
作為組件的屬性,把 input
作為給組件綁定事件時的事件名。
// 父組件
<my-button v-model="number"></my-button>
<script>
data() {
return {
number: 1,
}
}
</script>
// 子組件
<template>
<button @click="add">點擊按鈕自增 1</button>
</template>
<script>
export default {
props: {
value: Number, // 屬性名必須是 value
},
methods: {
add() {
this.$emit('input', this.value + 1) // 事件名必須是 input
},
}
}
</script>
有時間我們不想用 value
當做默認的屬性名,也不想把 input
當做事件名。能不能自定義呢?
在 Vue 2.2 及以上版本,你可以在定義組件時通過 model 選項的方式來定制 prop/event:↓
// 父組件
<my-button v-model="number"></my-button>
<script>
data() {
return {
number: 1,
}
}
</script>
// 子組件
<template>
<button @click="add">點擊按鈕自增 1</button>
</template>
<script>
export default {
model: {
prop: 'num', // 自定義屬性名
event: 'addNum' // 自定義事件名
},
props: {
num: Number,
},
methods: {
add() {
this.$emit('addNum', this.num + 1)
},
}
}
</script>
看到這里我相信你肯定理解了 Vue 的 v-model
,文中如有錯誤,歡迎在評論中指出,謝謝。
碼字辛苦,文章如對您有幫助,麻煩支持點贊~