Vue 的雙向繫結:v-model
寫在前面
Vue 框架早已經不是 MVVM(Mode-View-View-Model) 雙向綁定了。早在 Vue 1.0 時代,Vue 在剛出世的時候的確是 MVVM 雙向繫結。自 Vue 2.0 以來,Vue 就不再是雙向綁定了,而是像 React 一樣是單向繫結 MV(Model-View)了。但是,在 Vue 中仍保留了雙向繫結的介面,v-model 就是。
1. 基本用法
<template> <div id="app"> <input v-model="x"> {{x}} </div> </template> <script> export default { data(){ return { x: 'init' } } }
在 JS 中修改 x 的值,input 輸入框裡也會隨之改變。同樣地,在頁面中的 input 輸入框內手動輸入值,變數 x 的值也會隨之改變。物件裡的變數改變會影響檢視的 input 的改變,檢視中 input 的改變會影響物件裡變數 x 值的改變。這就是雙向繫結(Model-View-View-Model)。
2. v-model 實質
上述使用 v-model 的程式碼等價於如下程式碼:
<template> <div id="app"> <input :value="x" @input="x = $event.target.value"> {{x}} </div> </template> <script> export default { data(){ return { x: 'init' } } } </script>
v-model 幫我們做的事就是,為 input 的 value 值設定一個動態繫結,然後在輸入框的 input 事件觸發後實時修改動態繫結的 value 的變數值。因此 v-model 實質是上述方式的語法糖。
$event 是原生 DOM 事件裡的 event 事件物件。
其餘表單的輸入繫結詳見 vue 表單
3. v-model 的修飾符
所有修飾符都是起一個輔助的作用,其實可以在函式裡自己判斷條件實現。
.lazy
v-model 預設監聽的是輸入框的 input
事件,原生 DOM 的 input
事件就是記錄實時的輸入變化值。但是,我們有時不需要實時記錄結果,只需要記錄最終輸入的結果值就可以了。
input 的原生 DOM 事件中還有一個 change
.lazy
修飾符的方式切換至該監聽模式。
<template>
<div id="app">
<input v-model.lazy="x">
{{x}}
</div>
</template>
等價於:
<template>
<div id="app">
<input :value="x" @change="x = $event.target.value">
{{x}}
</div>
</template>
.number
.number
修飾符是在輸入內容改變後進行變數賦值時,自動使用 parseFloat() 函式將其變成數字。
使用該修飾符時變數的初始值必須是數字。
<template>
<div id="app">
<input v-model.number="x">
{{x}}
</div>
</template>
<script>
export default {
data(){
return {
x: 0
}
}
}
</script>
.trim
.trim
修飾符是將輸入的內容改變後進行變數賦值時,自動忽略和去除前後的空格。更為精準地記錄輸入的字串內容。
<template>
<div id="app">
<input v-model.trim="x">
{{x}}
</div>
</template>
<script>
export default {
data(){
return {
x: 'init'
}
}
}
</script>
4. 自定義輸入框的 v-model
v-model 的基本用法僅僅適用於 原生的輸入框元素,對於使用者自己封裝的輸入框,可以用如下方式使用 v-model。
當用在元件上時,v-model 的實質如下:
<custom-input v-model="x"></custom-input>
等價於:
<custom-input :value="x" @input="x = $event"></custom-input>
因此,在自定義表單元件裡的寫法如下:
<template>
<div class="wrapper">
<input :value="value" @input="$emit('input', $event.target.value)">
</div>
</template>
<script>
export default {
props: {
value: {
type: String
}
}
}
</script>
<style scoped>
.wrapper{
border: 2px solid blue;
display: inline-block;
}
.wrapper input{
color: red;
}
</style>
<template>
<div id="app">
<MyInput v-model="x"/>
{{x}}
</div>
</template>
<script>
import MyInput from './components/MyInput'
export default {
data(){
return {
x: 0
}
},
components:{
MyInput
}
}
</script>
補充:若想在自定義元件裡面的原生輸入框也使用 v-model,可以根據元件 v-model 的實質,使用計算屬性的賦值方式為 =
使用。