v-model常用于表单元素上进行数据的双向绑定,比如input、textarea、select等组件。除了原生元素,它还能再自定义组件中使用,比如弹框的显示与隐藏。
我们都知道,v-model实际上是一个语法糖,可以拆解为两部分,props: value和events: input。
注:v-model为不同的输入元素使用不同的属性并抛出不同的事件:input和textarea元素使用value属性和input属性,checkbox和radio元素使用checked属性和change属性 ,select元素使用value属性和input属性 。
就是说组件必须提供一个名为value的prop和一个名为input 的自定义事件,满足这两个条件,开发人员就能在自定义组件上使用v-model。比如下面的示例,实现了一个数字加减器。
<template>
<div>
<button @click="increase(-1)">减1</button>
<span style="color: brown; padding: 10px">{{currentValue}}</span>
<button @click="increase(1)">加1</button>
</div>
</template>
<script>
export default {
name: 'test',
props: {
value: {
type: Number
}
},
data() {
return {
currentValue: this.value
}
},
watch: {
value(val) {
this.currentValue = val;
}
},
methods: {
increase(val) {
this.currentValue += val;
this.$emit('input', this.currentValue);
}
}
}
</script>
props一般是不能在组件内修改,它是通过父组件修改,因此实现v-model一般都会有一个currentValue的内部data,初始时从props中的value获取一次值,当value修改,也会通过watch监听到并及时更新。组件内并不会修改value值,而是修改currentValue,同时将修改的值通过自定义事件input派发给父组件,父组件接收后,由父组件修改value的值。
<template>
<div>
<h3>This is a test demo</h3>
<TestModel :value="value" @input="handleChange"></TestModel>
</div>
</template>
<script>
import TestModel from './components/TestModel.vue'
export default {
name: 'App',
data () {
return {
value: 3
}
},
methods: {
handleChange(val) {
this.value = val;
}
},
components: {
TestModel
},
}
</script>
简单化,父组件可以直接用v-model:
<template>
<div>
<h3>This is a test demo</h3>
<TestModel v-model="value"></TestModel>
</div>
</template>
<script>
import TestModel from './components/TestModel.vue'
export default {
name: 'App',
components: {
TestModel
},
data () {
return {
value: 3
}
}
}
</script>
如果你不想用value和input这两个名字,从Vue 2.2.0版本开始,提供了一个model的选项,可以指定他们的名字。所以数字加减器也可以这样写:
<template>
<div>
<button @click="increase(-1)">减1</button>
<span style="color: brown; padding: 10px">{{currentValue}}</span>
<button @click="increase(1)">加1</button>
</div>
</template>
<script>
export default {
name: 'test',
props: {
digit: {
type: Number
}
},
model: {
prop: 'digit',
event: 'change'
},
data() {
return {
currentValue: this.digit
}
},
watch: {
digit(val) {
this.currentValue = val;
}
},
methods: {
increase(val) {
this.currentValue += val;
this.$emit('change', this.currentValue);
}
}
}
</script>
完结啦~