原生组件使用v-model
vue中,v-model指令可以实现表单<input>、<textarea>、<select>等元素的双向数据绑定。v-model本质上是语法糖,为不同的表单元素使用不同的属性值并抛出不同的事件。如下代码,v-model为input元素绑定了value属性和input事件。
<input v-model="searchText" />
等价于
<input :value="searchText" @input="searchText = $event.target.value" />
vue3自定义组件使用v-model
v-model指令
在自定义组件上使用v-model指令时,会给组件绑定一个model-value属性和一个update:model-value监听事件。
<custom-input v-model="searchText"></custom-input>
等价于
<custom-input
:model-value="searchText"
@update:model-value="searchText = $event"
></custom-input>
自定义组件内部会接收一个名为modelValue的props,和一个名为update:modelValue的emits。自定义组件将新值,通过emit(update:modelValue, value)将事件抛出,从而实现数据的双向绑定。
app.component('custom-input', {
props: ['modelValue'],
emits: ['update:modelValue'],
template: `
<input
:value="modelValue"
@input="$emit('update:modelValue', $event.target.value)"
>
`
})
v-model参数
v-model也可以接收一个参数,改变绑定的名称,如下代码,自定义组件,将接收一个名称为title的props和一个update:title的监听事件,自定义组件通过emit(update:title, value)抛出事件。
<ChildComponent v-model:title="pageTitle" />
<!-- 是以下的简写: -->
<ChildComponent :title="pageTitle" @update:title="pageTitle = $event" />
在自定义组件上使用多个v-model
可以给自定义组件设置多个v-model,下面代码中,组件有两个名为title和content的v-model。组件将接收title和content两个props,update:title和update:content两个emits,自定义组件通过emit(update:title)和emit(update:content)抛出事件。
<ChildComponent v-model:title="pageTitle" v-model:content="pageContent" />
<!-- 是以下的简写: -->
<ChildComponent
:title="pageTitle"
@update:title="pageTitle = $event"
:content="pageContent"
@update:content="pageContent = $event"
/>
举例说明
实现一个自定义组件,输入的小写字母自动转换成大写字母。
//使用自定义组件
<my-input v-model="myInputvalue"/>
{{myInputvalue}}
// MyInput.vue
<template>
<input :value="inputVal" @input="updateValue"/>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue'
export default defineComponent({
props: ['modelValue'],
emits: ['update:modelValue'],
setup (props, context) {
const inputVal = ref(props.modelValue.toUpperCase())
const updateValue = (e: KeyboardEvent) => {
const targetValue = (e.target as HTMLInputElement).value.toUpperCase()
inputVal.value = targetValue
context.emit('update:modelValue', targetValue)
}
return {
inputVal,
updateValue
}
}
})
</script>