核心思想
v-model
都是一个语法糖,用于简化表单输入元素和组件与数据状态之间的双向同步。
总结对比表
特性 | Vue 2 | Vue 3 |
---|---|---|
底层原理 | Object.defineProperty |
Proxy |
默认绑定 | :value + @input |
:modelValue + @update:modelValue |
组件绑定数量 | 仅限 1 个 | 可多个 (通过参数区分,如 v-model:title ) |
自定义修饰符 | 需手动处理,非常繁琐 | 内置支持 ,通过 modelModifiers prop 访问 |
替代方案 | 使用 .sync 修饰符实现多个"双向绑定" |
移除了 .sync ,其功能由多个 v-model 替代 |
一、底层实现原理不同
Vue 2: Object.defineProperty
- 机制 :通过递归遍历数据对象,使用
getter
和setter
拦截并监听每个属性。 - 缺点:
-
- 无法检测 对象属性的添加或删除 (需用
Vue.set
/this.$set
)。 - 无法监听****数组索引 和长度的变化。
- 无法检测 对象属性的添加或删除 (需用
- 影响 :
v-model
绑定的数据响应性有一定限制。
Vue 3: Proxy
- 机制 :创建一个对象的代理,从而拦截并监听对该对象的任何操作。
- 优点:
-
- 可检测任何属性的变化(包括增、删)。
- 完美监听数组的变化。
- 影响 :为
v-model
提供了更强大、更高效的底层响应式支持。
二、在自定义组件上的使用(最大变化)
Vue 2: 单一 v-model
一个组件上只能有一个 v-model
,它等价于传递 value
prop 和监听 input
事件。
父组件
xml
<ChildComponent v-model="pageTitle" />
<!-- 等价于 -->
<ChildComponent :value="pageTitle" @input="pageTitle = $event" />
子组件
xml
<template>
<input :value="value" @input="$emit('input', $event.target.value)" />
</template>
<script>
export default {
props: ['value']
}
</script>
Vue 2 的替代方案 :使用 .sync
修饰符实现多个"双向绑定"
xml
<ChildComponent :title.sync="pageTitle" />
<!-- 等价于 -->
<ChildComponent :title="pageTitle" @update:title="pageTitle = $event" />
Vue 3: 多个 v-model
(核心优势)
一个组件上可以绑定多个 v-model
,通过参数 来区分。默认的 v-model
使用 modelValue
和 update:modelValue
。
父组件
ruby
<UserName
v-model:first-name="firstName"
v-model:last-name="lastName"
/>
<!-- 等价于 -->
<UserName
:first-name="firstName"
:last-name="lastName"
@update:first-name="firstName = $event"
@update:last-name="lastName = $event"
/>
子组件 (使用 <script setup>
)
ini
<template>
<input
type="text"
:value="firstName"
@input="$emit('update:firstName', $event.target.value)"
/>
<input
type="text"
:value="lastName"
@input="$emit('update:lastName', $event.target.value)"
/>
</template>
<script setup>
defineProps({
firstName: String,
lastName: String
})
defineEmits(['update:firstName', 'update:lastName'])
</script>
三、处理自定义修饰符
Vue 3: 内置支持 (非常方便)
Vue 3 可以自动将修饰符传递给子组件。
父组件
ini
<MyComponent v-model.capitalize="text" />
子组件
xml
<template>
<input :value="modelValue" @input="emitValue" />
</template>
<script setup>
const props = defineProps({
modelValue: String,
modelModifiers: { // 固定命名:prop名 + "Modifiers"
default: () => ({}) // 默认为空对象
}
})
const emit = defineEmits(['update:modelValue'])
function emitValue(e) {
let value = e.target.value
// 检查是否有.capitalize修饰符
if (props.modelModifiers.capitalize) {
value = value.charAt(0).toUpperCase() + value.slice(1)
}
emit('update:modelValue', value)
}
</script>
对于带参数的 v-model
,修饰符对象名为 arg + "Modifiers"
。
例如:v-model:description.capitalize
对应的 prop 为 descriptionModifiers
。
Vue 2: 手动处理 (非常繁琐)
在 Vue 2 中实现类似功能需要更多步骤,包括使用 model
选项和计算属性,过程复杂。
核心结论
- 功能更强 :Vue 3 的
v-model
支持多个绑定,极大提升了组件的灵活性和复用性。 - API 更统一 :用参数化
v-model
取代了 Vue 2 中v-model
和.sync
共存的混乱局面,概念更清晰。 - 开发更便捷 :内置修饰符处理让创建功能丰富的自定义输入组件变得非常简单。
- 基础更稳固 :基于
Proxy
的实现,响应式追踪能力更强,性能更好。
总结:Vue 3 的 v-model
在灵活性、功能性和开发体验上都是对 Vue 2 的一次全面升级。