Vue 3组合式API中如何将子组件响应式变量传递给父组件
Vue子组件向父组件传递响应式数据的几种实用方法
方法1:使用defineEmits触发自定义事件
这是Vue官方推荐的子向父传值方案,子组件通过触发自定义事件传递数据,父组件监听事件接收数据,完全遵循单向数据流原则。
子组件(ExtraFormField.vue)
<script setup> import { ref } from 'vue' // 声明要触发的自定义事件 const emit = defineEmits(['update-field-data']) // 子组件自身的响应式字段 const fieldValue = ref('') // 输入变化时触发事件,把最新值传给父组件 const handleInput = () => { emit('update-field-data', fieldValue.value) } </script> <template> <input v-model="fieldValue" @input="handleInput" placeholder="填写额外字段内容" /> </template>
父组件(ParentForm.vue)
<script setup> import { ref } from 'vue' import ExtraFormField from './ExtraFormField.vue' // 父组件主表单字段 const mainField = ref('') // 存储所有子组件的字段数据 const extraFieldsData = ref([]) // 添加额外字段的方法 const addExtraField = () => { extraFieldsData.value.push('') } // 接收子组件传递的字段值,更新对应索引的数据 const updateExtraField = (value, index) => { extraFieldsData.value[index] = value } // 提交表单,整合所有数据传给API const submitForm = () => { const formData = { mainField: mainField.value, extraFields: extraFieldsData.value } // 这里替换为你的API调用逻辑 console.log('提交的完整表单数据:', formData) } </script> <template> <form @submit.prevent="submitForm"> <div> <label>主字段:</label> <input v-model="mainField" /> </div> <button type="button" @click="addExtraField" style="margin: 10px 0;">添加额外字段</button> <!-- 循环渲染子组件,通过索引绑定对应数据 --> <div v-for="(item, index) in extraFieldsData" :key="index"> <label>额外字段{{ index + 1 }}:</label> <ExtraFormField @update-field-data="(val) => updateExtraField(val, index)" /> </div> <button type="submit" style="margin-top: 10px;">提交表单</button> </form> </template>
方法2:使用自定义v-model实现双向绑定
如果子组件是单个输入类组件,可以用自定义v-model简化双向绑定,让父组件直接通过v-model绑定子组件的响应式数据。
子组件(ExtraFormField.vue)
<script setup> import { ref, defineProps, defineEmits, watch } from 'vue' // 接收父组件传递的初始值 const props = defineProps(['modelValue']) // 声明对应更新事件 const emit = defineEmits(['update:modelValue']) // 子组件内部响应式变量 const fieldValue = ref(props.modelValue) // 监听内部值变化,自动触发更新事件同步给父组件 watch(fieldValue, (newVal) => { emit('update:modelValue', newVal) }) </script> <template> <input v-model="fieldValue" placeholder="填写额外字段内容" /> </template>
父组件(ParentForm.vue)
<script setup> import { ref } from 'vue' import ExtraFormField from './ExtraFormField.vue' const mainField = ref('') const extraFieldsData = ref([]) const addExtraField = () => { extraFieldsData.value.push('') } const submitForm = () => { const formData = { mainField: mainField.value, extraFields: extraFieldsData.value } console.log('提交的完整表单数据:', formData) } </script> <template> <form @submit.prevent="submitForm"> <div> <label>主字段:</label> <input v-model="mainField" /> </div> <button type="button" @click="addExtraField" style="margin: 10px 0;">添加额外字段</button> <div v-for="(item, index) in extraFieldsData" :key="index"> <label>额外字段{{ index + 1 }}:</label> <!-- 直接用v-model绑定数组元素,自动同步子组件数据 --> <ExtraFormField v-model="extraFieldsData[index]" /> </div> <button type="submit" style="margin-top: 10px;">提交表单</button> </form> </template>
方法3:通过ref获取子组件实例一次性取值
如果只需要在表单提交时一次性获取所有子组件数据,可以给子组件添加ref,通过实例访问子组件暴露的响应式变量。
子组件(ExtraFormField.vue)
<script setup> import { ref } from 'vue' const fieldValue = ref('') // 把需要父组件访问的变量暴露出去 defineExpose({ fieldValue }) </script> <template> <input v-model="fieldValue" placeholder="填写额外字段内容" /> </template>
父组件(ParentForm.vue)
<script setup> import { ref } from 'vue' import ExtraFormField from './ExtraFormField.vue' const mainField = ref('') // 存储所有子组件的ref实例 const extraFieldRefs = ref([]) const addExtraField = () => { extraFieldRefs.value.push(null) } const submitForm = () => { // 遍历所有子组件实例,提取字段值 const extraFields = extraFieldRefs.value.map(ref => ref?.fieldValue.value) const formData = { mainField: mainField.value, extraFields: extraFields } console.log('提交的完整表单数据:', formData) } </script> <template> <form @submit.prevent="submitForm"> <div> <label>主字段:</label> <input v-model="mainField" /> </div> <button type="button" @click="addExtraField" style="margin: 10px 0;">添加额外字段</button> <div v-for="(item, index) in extraFieldRefs" :key="index"> <label>额外字段{{ index + 1 }}:</label> <!-- 绑定ref到数组对应位置 --> <ExtraFormField ref="el => extraFieldRefs[index] = el" /> </div> <button type="submit" style="margin-top: 10px;">提交表单</button> </form> </template>
方案对比
- defineEmits:最通用的方案,适合实时同步数据的场景,完全符合Vue单向数据流设计。
- 自定义v-model:代码最简洁,适合单个输入字段的双向绑定场景。
- ref获取实例:适合仅在提交时一次性取值的场景,无需实时同步数据。
内容的提问来源于stack exchange,提问作者oduwa
相关产品推荐
相关产品推荐

