v-model
主要用于进行表单项的输入绑定,本质上只是一个语法糖,它负责监听用户的输入事件以更新数据。
当在自定义组件中使用v-model
时,组件接收一个属性value
的值,然后通过触发input
事件来更新该值,这样便实现了v-model
:
<my-input v-model="value"></my-input>
<!-- 相当于 -->
<my-input :value="value" @input="value=$event.target.value"></my-input>
实现my-input
组件:
<template>
<div>
<input type="text" :value="value" @input="handleInput"/>
</div>
</template>
<script>
export default {
name: "myinput",
props:{
value: String
},
methods:{
handleInput(e){
this.$emit('input', e.target.value) //触发父组件的input事件
}
}
}
</script>
v-model
在vue2
中使用存在一个问题:那就是传递下去的必须是value
值,接收的也必须是input
事件。但是并不是所有的元素都适合传递value
,这时候就可以通过model来指定v-model
绑定的值和属性
<template>
<div>
<input :value="v" @input="handleInput"/>
</div>
</template>
<script>
export default {
name: "myinput",
model: {
prop: 'v', // default: value
event: 'i', // default: input
},
props:{
v: String
},
methods:{
handleInput(e){
this.$emit('i', e.target.value) //触发父组件的input事件
}
}
}
</script>
model属性
指定了两个属性:prop
和event
,这就是 v-model
的属性和事件名,他们的默认值为value
和input
,我们通过修改model
属性的 prop
和 event
就实现了自定义。
lazy:将触发input
事件转为触发change
事件,在某些场景下来降低数据同步频率提升性能。
<!-- 在“change”时而非“input”时更新 -->
<input v-model.lazy="msg" />
number:自动将用户的输入值转为数值类型。
<input v-model.number="age" type="number" />
trim:自动过滤用户输入的首尾空白字符
<input v-model.trim="msg" />
当在自定义组件中使用v-model
时,组件接收一个属性modelValue
的值,然后通过触发update:modelValue
事件来更新该值:
<my-input v-model="value"></my-input>
<!-- 相当于 -->
<my-input :model-value="value" @update:model-value="value=$event.target.value"></my-input>
实现my-input
组件:
<template>
<input :value="modelValue" @input="handleInput">
</template>
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
props: ['modelValue'],
setup(props, context) {
const handleInput = (e) => {
context.emit('update:modelValue', e.target.value)
}
return {
handleInput
}
}
})
</script>
// 使用
<my-input v-model="value"></my-input>
Vue3
的 v-model
是接收属性modelValue
的值,然后触发事件update:modelValue
来更新该值,这个属性名也可以修改,只需要给v-model
添加参数即可,比如:v-model:hry
,这样就将modelValue
换成了hry
。
<template>
<input :value="hry" @input="handleInput">
</template>
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
props: ['hry'],
setup(props, context) {
const handleInput = (e) => {
context.emit('update:hry', e.target.value)
}
return {
handleInput
}
}
})
</script>
// 使用
<my-input v-model:hry="value"></my-input>;
在 vue3
中新增了 v-model
的参数传递,所以自定义组件可以同时支持多个v-model
的绑定:
<my-input v-model:hry="hry" v-model:roy="roy"></my-input>
实现my-input
组件:
<template>
<input :value="hry" @input="e => handleInput(e, 'hry')">
<input :value="roy" @input="e => handleInput(e, 'roy')">
</template>
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
props: ['hry', 'roy'],
setup(props, context) {
const handleInput = (e, name) => {
context.emit(`update:${name}`, e.target.value);
}
return {
handleInput
}
}
})
</script>
不同于 vue2 的硬编码,在 vue3 中支持自定义修饰符:
<my-input v-model.cpas="bar"></my-input>
组件接收自定义修饰符:
<template>
<input :value="modelValue" @input="emitValue">
</template>
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
props: {
modelValue: String,
// 组件接收属性modelModifiers对象,对象里面包含多个修饰符,这里默认给个空对象:{}
modelModifiers: {
default: () => ({}),
},
},
setup(props, context) {
// 实现修饰符`capitalize`,将 v-model 绑定的值首字母大写
const emitValue = (e) {
let v = e.target.value;
if (this.modelModifiers.cpas) {
v = v.charAt(0).toUpperCase() + v.slice(1);
}
this.emit('update:modelValue', v);
}
return {
emitValue
}
}
})
</script>
组件会接收一个属性为modelModifiers
的对象,上面示例给出了默认值{}
,然后在生命周期函数created
中拿到了修饰符capitalize的值为true
(因为在上面组件使用时绑定了v-model.capitalize="bar"
)。