Vue父子组件v-model传值交互总结
概述
总结了Vue 3中父子组件之间使用v-model进行数据双向绑定的各种实现方式,包括普通类型和引用类型的处理。
文件结构
demo.vue
- 父组件,使用v-model向子组件传递数据child.vue
- 子组件,接收父组件数据并支持双向绑定
父组件实现 (demo.vue)
vue
<template>
<div class="p-100px">
<h1>{{ obj.count }}</h1>
// 引用类型
<Child v-model:obj="obj" />
// 普通类型
<Child v-model:count="count" />
</div>
</template>
<script setup lang="ts">
import Child from '@/views/components/child.vue'
import { ref } from 'vue'
const count = ref(0)
const obj = ref({
count: 0,
})
</script>
关键点:
- 使用
v-model:obj="obj"
语法向子组件传递对象 - 父组件维护响应式数据
obj
子组件实现方式
普通类型传值
方法1:使用 ref + watch
typescript
import { ref, watch } from 'vue'
const props = defineProps({
count: {
type: Number,
default: 0,
},
})
const emit = defineEmits(['update:count'])
const count = ref(props.count)
watch(count, (newVal) => {
emit('update:count', newVal)
})
方法2:使用 computed
typescript
import { computed } from 'vue'
const props = defineProps({
count: {
type: Number,
default: 0,
},
})
const emit = defineEmits(['update:count'])
const count = computed({
get: () => props.count,
set: (value) => emit('update:count', value),
})
方法3:使用 defineModel (推荐)
typescript
const count = defineModel('count')
方法4:使用 @vueuse/core
typescript
import { useVModel } from '@vueuse/core'
const props = defineProps({
count: {
type: Number,
default: 0,
},
})
const count = useVModel(props, 'count')
引用类型传值
方法1:使用 ref + watch (深度监听)
typescript
import { ref, watch } from 'vue'
const props = defineProps({
obj: {
type: Object,
default: () => ({}),
},
})
const emit = defineEmits(['update:obj'])
const obj = ref(props.obj)
watch(
obj,
(newVal) => {
emit('update:obj', newVal)
},
{ deep: true },
)
方法2:使用 defineModel (推荐)
typescript
interface Obj {
count: number
}
const obj = defineModel<Obj>('obj')
最佳实践建议
1. 优先使用 defineModel
- Vue 3.4+ 版本推荐使用
defineModel
- 代码更简洁,性能更好
- 自动处理 props 和 emit
2. 引用类型处理
- 对于对象类型,使用
defineModel
配合 TypeScript 接口 - 确保类型安全,提供更好的开发体验
3. 命名规范
- v-model 的自定义名称应该语义化
- 如
v-model:userInfo
、v-model:formData
等
4. 类型定义
- 使用 TypeScript 接口定义复杂对象类型
- 提供更好的代码提示和类型检查
实际应用示例
当前项目中的实现展示了引用类型的双向绑定:
父组件传递:
vue
<Child v-model:obj="obj" />
子组件接收:
vue
<input type="text" class="border" v-model="obj.count" />
这种方式允许子组件直接修改父组件传递的对象属性,实现真正的双向数据绑定。
总结
Vue 3 提供了多种方式实现父子组件的双向数据绑定:
- defineModel - 最推荐的方式,简洁高效
- computed - 适合需要额外逻辑处理的场景
- ref + watch - 传统方式,适合复杂场景
- @vueuse/core - 第三方库,提供更多功能
选择合适的方式取决于具体需求和项目复杂度,但建议优先考虑 defineModel
方式。