看完官网API的介绍,想必是有点懵的,我们可以从v-mode的语法糖来一步一步的理解。
v-mode语法糖:
v-model实现了表单输入的双向绑定。一般我们是这么写的:
// html
<div>
<input v-model="name" />
</div>
// .vue文件
export default {
data(){
return {
name: '',
}
}
}
如何实现双向数据的绑定?其实分为两步:
第一步:将变量name的值绑定到input输入框的值上,即改变name的值可以改变输入框的值。
第二步:监听输入框的Input事件,如果输入框的值发生改变就改变name的值。
所以v-model语法糖的真正的实现是这样的:
// html
<div>
<input :value="name" @input="inputName($event)" />
</div>
// .vue文件
export default {
data(){
return {
name: '',
}
},
methods: {
inputName(){
this.name = $event.tatget.value;
}
}
}
那现在我们来看一下在自定义组件上使用v-model是如何分解的:
// 父组件
<div>
<name-input v-model="name"></name-input> // v-mode语法糖
</div>
<div>
<name-input :value="name" @input="nameInput"></name-input> // 使用prop传递和事件传递
</div>
export default {
data(){
return {
name: '',
}
},
methods: {
nameInput(val){
this.name = val;
}
}
}
// 子组件
Vue.component('name-input',{
template:'<input type="text" :value="value" @input="update($event)" />',
props:['value'],
methods:{
update(e){
this.$emit('input', e.target.value);
}
}
})
总结一下:
自定义事件也可以用于创建支持 v-model
的自定义输入组件。记住:
<input v-model="searchText">
等价于:
<input
v-bind:value="searchText"
v-on:input="searchText = $event.target.value"
>
当用在组件上时,v-model
则会这样:
<custom-input
v-bind:value="searchText"
v-on:input="searchText = val" // val是在父组件中接收$emit传过来的值
></custom-input>
为了让它正常工作,这个组件内的 <input>
必须:
- 将其
value
特性绑定到一个名叫value
的 prop 上 。<input :value="value"/>标红的value实际是一个prop,只是名字叫value。 - 在其
input
事件被触发时,将新的值通过自定义的input
事件抛出。标红的input事件其实是@input,即在子组件$emit事件触发的函数,$emit('input', 传参) 。 <custom-input :value="searchText" @input="searchText = val" ></custom-input>
写成代码之后是这样的:
Vue.component('custom-input', {
props: ['value'],
template: `
<input
v-bind:value="value"
v-on:input="$emit('input', $event.target.value)"
>
`
})
现在 v-model
就应该可以在这个组件上完美地工作起来了:
<custom-input v-model="searchText"></custom-input>
v-model的语法糖理清楚了,那现在来看model的用法,官网API是这样说的:
可以理解为:model默认为 model:{ prop: 'value', event: 'input'},当使用默认值时 model可以不写,如下:
// 子组件
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<input type="checkbox" @input="change($event)" />
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data () {
return {
msg: 'Welcome to Your Vue.js App'
}
},
methods: {
change(e){
console.log(e.target.checked,'111')
this.$emit('input', e.target.checked)
}
}
}
</script>
// 父组件
<template>
<div id="app">
<h3 class="title">{{ msg }}</h3>
<hello-world v-model="msg"/>
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
export default {
components:{
HelloWorld
},
data () {
return {
msg: 'vue-demo向你问好!',
}
}
}
</script>
但是当prop 的默认值不是value,event的默认值不是input时就需要添加model,如下:
// 子组件
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<input type="checkbox" @change="change($event)" :checked= "checked" /> // checked是model.prop的值
</div>
</template>
<script>
export default {
name: 'HelloWorld',
model: {
prop: 'checked',
event: 'checkChange'
},
props:['checked'],
data () {
return {
msg: 'Welcome to Your Vue.js App'
}
},
methods: {
change(e){
console.log(e.target.checked,'111')
this.$emit('checkChange', e.target.checked) // checkChange 是model.event的值
}
}
}
</script>
// 父组件
<template>
<div id="app">
<h3 class="title">{{ msg }}</h3>
<hello-world v-model="msg"></hello-world>
<button @click="changeCheck">改变</button>
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
export default {
components:{
HelloWorld
},
data () {
return {
msg: true,
}
},
methods:{
changeCheck(){
this.msg =!this.msg
}
}
}
</script>