传统双向绑定的痛点
在 defineModel 出现之前,Vue 的双向绑定主要依赖于 v-model 和手动管理 props 和 emits。虽然这些方法有效,但在复杂场景下,代码往往显得冗长且难以维护。
方案一:手动管理 props 和 emits
父组件传递数据的同时需要实现一个修改数据的方法传递给子组件
<!-- 父组件 -->
<child :carObj="carObj" @carPriceAdd="carPriceAdd" />
<script setup lang="ts">
const carObj = ref<ICarObj>({
brand: 'BMW',
price: 100000
})
const carPriceAdd = () => {
carObj.value.price += 1000
}
</script>
子组件接收数据的同时还需要接收父组件传递过来的事件,并通过emits触发调用,就可以修改父组件的数据了
<script setup lang="ts">
const props = defineProps<{
modelValue: IUser, // v-model
carObj: ICarObj // v-bind
}>()
const emits = defineEmits(['carPriceAdd'])
const priceAdd = () => {
emits('carPriceAdd')
console.log(props.carObj.price)
}
</script>
方案二:使用 v-model
还可以借助v-model,可以省去父组件定义修改数据的方法并传递给子组件这一步
父组件通过v-model传递数据给子组件
<child v-model="user" />
<script setup lang="ts">
const user = ref<IUser>({
name: 'song',
age: 18
})
</script>
子组件在接受数据的同时也还要接受事件,只不过这个事件并不是父组件显式传递过来的,并且格式有点区别
<script setup lang="ts">
const props = defineProps<{
modelValue: IUser, // v-model
carObj: ICarObj // v-bind
}>()
const emits = defineEmits(['update:modelValue'])
const ageAdd = () => {
emits('update:modelValue', {
...props.modelValue,
age: props.modelValue.age + 1
})
// console.log(props.modelValue.age)
}
</script>
v-model默认传递过来的参数名为:modelValue,默认传递过来的事件为:update:modelValue
默认参数名在父组件中可以修改,格式为:v-model:name,同理子组件中接受的数据名与事件名改成一致即可
尽管 v-model 简化了部分代码,但仍需手动管理 props 和 emits,尤其是在处理多个双向绑定时,代码复杂度显著增加。所以从 Vue 3.4 开始,官方更加推荐使用 defineModel() 宏来实现双向数据绑定。
defineModel 的诞生:简化双向绑定
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。