你可以用 v-model 指令在表单 <input>、<textarea> 及 <select> 元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。尽管有些神奇,但 v-model 本质上不过是语法糖。它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理
v-model 在内部为不同的输入元素使用不同的 property 并抛出不同的事件:
- text 和 textarea 使用
value
作为 prop 和 使用input
作为事件;- checkbox 和 radio 使用
checked
作为 prop 和 使用change
作为事件;- select 使用
value
作为 prop 和 使用change
作为事件;
v-model 的原理
v-model 的原理其实是背后有两个操作
1、v-bind 绑定 value 属性的值;
2、v-on 绑定 input 事件监听到函数中,函数会获取最新的值赋值到绑定的属性中;
// 在原生元素上使用 v-model 时
<input v-model="searchText">
等价于:
<input :value="searchText" @input="searchText = $event.target.value">
那 v-model 是单向数据流吗?
是的,虽然官方没有明确表示这点,但我们可以捋一捋两者的关系。
什么是单项数据流?
父组件可以向子组件传递数据,并且改变子组件的值,而子组件不能改变父组件传递给它的 prop 属性,官方推荐的做法是子组件抛出事件,通知父组件自行改变绑定的值。
v-model 做法完全符合单项数据流。甚至于,它给出了一种在命名和事件定义上的规范。
众所周知 .sync 修饰符是单向数据流的另一个典型范式。
单向数据流:总结起来其实也就 8 个字:数据向下,事件向上
v-model 的特殊用法
一般情况,咱们使用 v-model 主要是用于数据的双向绑定,可以十分方便的获取到用户的输入值。
但在某些特殊情况下,我们也可以将 v-model 用于父子组件之间数据的双向绑定(在组件上使用 v-model)
// 当在组件上使用 v-model 时
<custom-input v-model="searchText"></custom-input>
等价于:
<custom-input :value="searchText" @input="searchText = $event"></custom-input>
例如:
// 父组件
<template>
<div id="app">
<custom-input v-model="userName"></custom-input>
</div>
</template>
<script>
import CustomInput from './components/custom-input'
export default {
name: 'App',
components: { CustomInput },
data(){
return {
userName: ''
}
}
}
</script>
// 子组件
<template>
<div class="custom-input">
<input type="text" :value="value" @input="handleInput"/>
</div>
</template>
<script>
export default {
name: "custom-input",
props: {
value:{ // 获取父组件的数据 value
type: String,
default: ''
}
},
methods: {
handleInput(e){
this.$emit('input', e.target.value) // 触发父组件的 input 事件
}
}
}
</script>
自定义组件的 v-model
默认情况下,一个组件上的 v-model 会把 value 用作 prop 且把 input 用作 event,
但是一些输入类型比如单选框和复选框按钮可能想使用value
prop 来达到不同的目的。使用model
选项可以回避这些情况产生的冲突
// 子组件
<template>
<div class="custom-checkbox">
<input type="checkbox" :checked="checked" @change="handleChange" />
</div>
</template>
<script>
export default {
name: "custom-checkbox",
// 允许一个自定义组件在使用 v-model 时定制 prop 和 event
model: {
prop: 'checked',
event: 'change'
},
props: {
checked:{ // 获取父组件的数据 checked
type: Boolean,
default: false
},
value: String,
},
methods: {
handleChange(e){
this.$emit('change', e.target.checked) // 触发父组件的 change 事件
}
}
}
</script>
现在 在这个组件上使用 v-model 的时候
<custom-checkbox v-model="isUserName" value="some value"></custom-checkbox>
等价于:
<custom-checkbox :checked="isUserName" @change="isUserName = $event" value="some value"></custom-checkbox>
这里的 isUserName 的值将会传入这个名为 checked 的 prop。同时当 <custom-checkbox> 触发一个 change 事件并附带一个新的值的时候,
这个 isUserName 的 property 将会被更新。
注意:你仍然需要在组件的 props 选项里声明 checked 这个 prop