You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 03:53:17