遵守 Vue3 的单向数据流原则:父组件传递对象 + 子组件修改对象属性,安全地实现父子组件之间复杂对象的双向绑定示例代码及讲解
以下是针对 父组件传递对象 + 子组件修改对象属性 的完整示例代码,同时遵守 Vue3 的单向数据流原则:
1. 父组件代码 (ParentComponent.vue)
vue
<template><!-- 通过 v-model 传递整个对象 --><ChildComponent v-model="formData" /><!-- 显示数据变化 --><div>父组件数据:{{ formData }}</div> </template><script setup> import { reactive } from 'vue'; import ChildComponent from './ChildComponent.vue';// 父组件数据(包含多个属性) const formData = reactive({name: '张三',age: 25,address: {city: '北京',street: '朝阳区'},email: 'zhangsan@example.com' }); </script>
2. 子组件代码 (ChildComponent.vue)
vue
<template><div><!-- 绑定对象属性 --><el-input v-model="localForm.name" placeholder="姓名" /><el-input v-model="localForm.age" placeholder="年龄" type="number" /><el-input v-model="localForm.address.city" placeholder="城市" /><el-input v-model="localForm.email" placeholder="邮箱" /></div> </template><script setup> import { computed } from 'vue';const props = defineProps(['modelValue']); const emit = defineEmits(['update:modelValue']);// 核心:通过计算属性实现双向绑定 const localForm = computed({get: () => props.modelValue,set: (newValue) => {// 触发更新事件,通知父组件emit('update:modelValue', newValue);} }); </script>
3. 方案解析
为什么能直接修改对象属性?
-
响应式原理:父组件通过
reactive()
创建响应式对象,子组件通过computed
的set
方法触发更新。 -
数据流安全:虽然看似直接修改了对象属性,但实际上是通过
emit
让父组件更新自己的数据,符合单向数据流。
注意事项
-
不要直接赋值整个对象:
js
// ❌ 错误!这会导致失去响应性 localForm.value = { ...localForm.value, name: '李四' };// ✅ 正确!Vue 会追踪对象内部属性的变化 localForm.value.name = '李四';
-
嵌套对象更新:如果修改深层属性(如
address.city
),需确保父组件对象是reactive
创建的。
4. 扩展:使用 defineModel
(Vue 3.4+)
如果使用 Vue 3.4+ 的 defineModel,可以进一步简化代码:
vue
<script setup> // 子组件 (ChildComponent.vue) const model = defineModel(); // 自动处理 v-model 绑定// 直接修改属性即可(底层自动触发 emit) const handleChange = () => {model.value.name = '李四'; }; </script>
5. 最终效果
-
父组件数据会随着子组件的修改自动更新。
-
所有修改都通过 Vue 的响应式系统追踪,无直接操作 props 的风险。
常见问题解决
Q:为什么修改子组件后父组件数据没变?
-
确保父组件数据用
reactive
或ref
创建。 -
不要解构父组件对象(如
const { name } = formData
会失去响应性)。
Q:如何修改嵌套对象属性?
直接修改即可(得益于 Vue 的响应式系统):
js
// 子组件中 localForm.value.address.city = '上海'; // 自动触发更新
通过这个方案,你可以在保持代码简洁的同时,安全地实现 父子组件间复杂对象的双向绑定。