v-model 在vue2与vue3中的差别
v-model 在vue2与vue3中的差别
Vue 2 与 Vue 3 中 v-model 的核心差异主要体现在语法设计、功能扩展和底层实现上。以下是两者的详细对比:
一、默认绑定行为
1. Vue 2
• 语法糖:v-model 默认绑定到 value 属性,监听 input 事件。
• 编译结果:
<ChildComponent v-model="data" />
<!-- 等价于 -->
<ChildComponent :value="data" @input="data = $event" />
• 自定义组件:需通过 model 选项指定 prop 和 event:
// 子组件配置
export default {
model: { prop: 'checked', event: 'change' },
props: ['checked'],
methods: { emitChange() { this.$emit('change', newValue); } }
}
2. Vue 3
• 语法糖升级:默认绑定到 modelValue 属性,监听 update:modelValue 事件。
• 编译结果:
<ChildComponent v-model="data" />
<!-- 等价于 -->
<ChildComponent :modelValue="data" @update:modelValue="data = $event" />
• 无需额外配置:子组件直接通过 defineProps 和 defineEmits 声明。
二、多 v-model 绑定支持
1. Vue 2
• 限制:每个组件仅支持单个 v-model,需通过 .sync 修饰符实现多属性双向绑定:
<ChildComponent :title.sync="title" :content.sync="content" />
2. Vue 3
• 原生支持多绑定:通过 v-model:propName 语法实现:
<UserForm v-model:name="userName" v-model:age="userAge" />
• 子组件处理:
// 子组件声明
const props = defineProps(['name', 'age']);
const emit = defineEmits(['update:name', 'update:age']);
三、自定义组件配置差异
1. Vue 2
• 依赖 model 选项:需显式指定 prop 和事件名。
• 示例:
export default {
model: { prop: 'selected', event: 'change' },
props: ['selected'],
methods: { handleChange() { this.$emit('change', newValue); } }
}
2. Vue 3
• 直接声明:使用 Composition API 的 defineProps 和 defineEmits:
// 子组件声明
const props = defineProps(['modelValue']);
const emit = defineEmits(['update:modelValue']);
四、事件处理与参数传递
1. Vue 2
• 固定事件名:仅支持 input 事件,需通过 model 选项自定义事件名。
• 参数限制:事件默认传递单个值(如 $event 为直接数据)。
2. Vue 3
• 灵活事件名:事件名为 update:propName,支持任意参数。
• 示例:
// 子组件触发事件
emit('update:modelValue', newValue);
五、性能与语法简洁性
• Vue 2 痛点:
• 多属性绑定需依赖 .sync,语法冗余。
• 无法直接监听复杂数据结构(如 Map、Set)的变化。
• Vue 3 优化:
• Tree Shaking 支持:未使用的 v-model 相关代码不会被打包。
• 更简洁的语法:通过 v-model:propName 直接绑定,无需额外配置。
总结对比表
| 特性 | Vue 2 | Vue 3 |
|---|---|---|
| 默认绑定 | value + input 事件 | modelValue + update:modelValue 事件 |
| 多绑定支持 | 需 .sync 修饰符 | 原生支持 v-model:propName |
| 自定义组件配置 | 需 model 选项 | 直接通过 defineProps/defineEmits |
| 事件灵活性 | 固定 input 事件 | 自定义 update:propName 事件 |
| 语法简洁性 | 冗余配置较多 | 语法统一,配置简洁 |
使用场景建议
• Vue 2 项目:
• 单数据流场景直接使用 v-model。
• 多属性绑定使用 .sync。
• Vue 3 项目:
• 优先使用 v-model:propName 实现多属性绑定。
• 结合 Composition API 提升代码可维护性。
通过以上对比,Vue 3 的 v-model 在设计上更灵活、功能更强大,显著提升了开发效率和代码可读性。
vue 3.4 的v-model
Vue 3.4 对 v-model 的实现进行了重大升级,引入 defineModel 宏作为双向绑定的官方推荐方案。以下是基于最新规范的核心用法和底层机制解析:
一、核心语法升级:defineModel 宏
1. 基础用法
<!-- 子组件 Child.vue -->
<script setup>
const model = defineModel() // 默认绑定 modelValue 属性和 update:modelValue 事件
</script>
<template>
<input v-model="model" />
</template>
• 父组件只需直接使用 v-model:
<Child v-model="count" />
• 底层机制:defineModel 会被编译为 modelValue prop 和 update:modelValue 事件。
2. 多参数绑定
支持为不同属性绑定多个 v-model:
<!-- 父组件 -->
<Child v-model:title="title" v-model:content="content" />
<!-- 子组件 -->
<script setup>
const title = defineModel('title')
const content = defineModel('content')
</script>
• 通过 v-model:param 指定参数名,子组件用 defineModel('param') 接收。
二、高级配置与验证
1. Prop 选项配置
const model = defineModel({
type: String,
required: true,
default: 'Hello'
})
• 支持标准 prop 验证规则(如类型校验、必填项等)。
2. 修饰符处理
<!-- 父组件使用修饰符 -->
<Child v-model.uppercase.trim="text" />
<!-- 子组件处理修饰符 -->
<script setup>
const [model, modifiers] = defineModel({
set(value) {
return modifiers.uppercase ? value.toUpperCase() : value
}
})
</script>
• 通过解构 modifiers 对象识别 .trim、.number 或自定义修饰符。
三、复杂数据类型的默认值
针对对象/数组类型需特殊处理:
const model = defineModel({
default: () => ({}),
get(val) {
return reactive(val || {}) // 确保默认值为响应式对象
}
})
• 注意:直接给复杂类型设置 default: [] 会导致多个实例共享同一引用。
四、与传统写法的对比
Vue 3.4 之前:
<script setup>
const props = defineProps(['modelValue'])
const emit = defineEmits(['update:modelValue'])
</script>
<template>
<input
:value="props.modelValue"
@input="emit('update:modelValue', $event.target.value)"
/>
</template>
• 缺点:需手动声明 props 和 emits,代码冗余。
Vue 3.4 优势:
• 代码简洁性:减少 50% 模板代码;
• 类型安全:自动推导 TypeScript 类型;
• 维护性:统一响应式变量操作接口。
五、底层原理与注意事项
-
Ref 特性
defineModel()返回的model是一个 Ref 对象,直接修改.value会触发父组件更新。 -
响应式同步
• 子组件修改model.value→ 触发update:modelValue事件 → 父组件更新值;
• 父组件值变化 → 自动同步到子组件的model.value。 -
性能优化
通过编译时静态分析生成高效代码,减少运行时开销。
六、迁移建议
-
旧项目升级
• 使用defineModel逐步替换defineProps+defineEmits组合;
• 复杂场景可用computed包装实现中间逻辑。 -
常见问题
• Q: 直接修改model.value可能导致 props 污染?
A:defineModel内部已隔离处理,无需担心。
总结对比表
| 特性 | Vue 3.4 (defineModel) | Vue 3.4 前传统写法 |
|---|---|---|
| 代码量 | 1 行声明 | 需 props + emits 声明(3+行) |
| 多参数支持 | 原生支持 v-model:param | 需手动配置多个 prop/emit |
| 类型推导 | 自动推断 TypeScript 类型 | 需手动标注类型 |
| 维护成本 | 低(统一接口) | 高(分散逻辑) |
通过 defineModel,Vue 3.4 实现了双向绑定逻辑的标准化和工程化,显著提升开发效率和代码可维护性。
评论