以下是 Vue 中自定义组件 v-model
语法的详细解析和具体示例,涵盖 Vue 2 和 Vue 3 的实现差异:
一、v-model
的核心原理
v-model
是语法糖,本质是 属性绑定(Prop) + 事件监听(Event) 的组合,用于实现双向数据绑定。
不同场景下的默认行为:
场景 | Vue 2 默认行为 | Vue 3 默认行为 |
---|---|---|
原生表单元素 | :value + @input |
:modelValue + @update:modelValue |
自定义组件 | :value + @input |
:modelValue + @update:modelValue |
二、Vue 2 中的自定义组件 v-model
1. 默认行为
- 父组件 :
v-model
绑定数据。 - 子组件 :接收
value
prop,通过input
事件更新数据。
示例:自定义输入组件
vue
<!-- 子组件 CustomInput.vue -->
<template>
<input
:value="value"
@input="$emit('input', $event.target.value)"
>
</template>
<script>
export default {
props: ['value']
};
</script>
vue
<!-- 父组件 -->
<template>
<CustomInput v-model="message" />
<p>输入内容:{{ message }}</p>
</template>
<script>
export default {
data() {
return { message: '' };
}
};
</script>
2. 自定义 Prop 和事件
通过 model
选项修改默认的 value
和 input
:
vue
<!-- 子组件 CustomCheckbox.vue -->
<template>
<input
type="checkbox"
:checked="checked"
@change="$emit('change', $event.target.checked)"
>
</template>
<script>
export default {
model: {
prop: 'checked', // 指定绑定的 prop
event: 'change' // 指定触发的事件
},
props: ['checked']
};
</script>
vue
<!-- 父组件 -->
<template>
<CustomCheckbox v-model="isChecked" />
</template>
三、Vue 3 中的自定义组件 v-model
1. 默认行为
- 父组件 :
v-model
绑定数据。 - 子组件 :接收
modelValue
prop,通过update:modelValue
事件更新数据。
示例:自定义输入组件
vue
<!-- 子组件 CustomInput.vue -->
<template>
<input
:value="modelValue"
@input="$emit('update:modelValue', $event.target.value)"
>
</template>
<script setup>
defineProps(['modelValue']);
defineEmits(['update:modelValue']);
</script>
vue
<!-- 父组件 -->
<template>
<CustomInput v-model="message" />
<p>输入内容:{{ message }}</p>
</template>
<script setup>
import { ref } from 'vue';
const message = ref('');
</script>
2. 多 v-model
绑定
Vue 3 支持为单个组件绑定多个 v-model
,通过参数区分不同数据。
示例:用户信息表单组件
vue
<!-- 子组件 UserForm.vue -->
<template>
<input
:value="username"
@input="$emit('update:username', $event.target.value)"
>
<input
:value="email"
@input="$emit('update:email', $event.target.value)"
>
</template>
<script setup>
defineProps(['username', 'email']);
defineEmits(['update:username', 'update:email']);
</script>
vue
<!-- 父组件 -->
<template>
<UserForm
v-model:username="user.name"
v-model:email="user.email"
/>
<p>用户名:{{ user.name }}</p>
<p>邮箱:{{ user.email }}</p>
</template>
<script setup>
import { reactive } from 'vue';
const user = reactive({ name: '', email: '' });
</script>
四、高级用法:自定义修饰符
通过 v-model
的修饰符扩展功能(如自动转大写)。
示例 :自定义输入组件支持 .uppercase
修饰符
vue
<!-- 子组件 CustomInput.vue -->
<template>
<input
:value="modelValue"
@input="handleInput"
>
</template>
<script setup>
const props = defineProps({
modelValue: String,
modelModifiers: { // 自动接收修饰符对象
type: Object,
default: () => ({})
}
});
const emit = defineEmits(['update:modelValue']);
const handleInput = (e) => {
let value = e.target.value;
if (props.modelModifiers.uppercase) {
value = value.toUpperCase();
}
emit('update:modelValue', value);
};
</script>
vue
<!-- 父组件 -->
<template>
<CustomInput v-model.uppercase="text" />
<p>大写内容:{{ text }}</p>
</template>
<script setup>
import { ref } from 'vue';
const text = ref('');
</script>
五、Vue 2 与 Vue 3 的对比总结
特性 | Vue 2 | Vue 3 |
---|---|---|
默认 Prop/事件 | value + input |
modelValue + update:modelValue |
多 v-model 支持 |
不支持(需用 .sync ) |
支持(v-model:arg ) |
修饰符处理 | 通过 model 选项配置 |
通过 modelModifiers 自动接收 |
语法简洁性 | 需要额外配置 model 选项 |
更直观,支持 <script setup> |
六、最佳实践
- 明确命名 :使用有意义的参数名(如
v-model:username
),避免歧义。 - 单向数据流:子组件通过事件更新数据,不直接修改 Prop。
- 修饰符扩展 :通过
modelModifiers
灵活扩展组件功能。 - TypeScript 支持:在 Vue 3 中结合类型定义提升代码健壮性。
通过合理利用 v-model
,可以显著简化父子组件间的双向数据绑定逻辑,提升代码可维护性。