在Vue3中,子组件向父组件传递数据主要通过自定义事件的方式实现,核心原理是子组件通过emit触发事件并携带数据,父组件监听该事件并接收数据。以下是具体实现方法和示例:

方法说明

  1. 子组件:通过 emit 方法触发一个自定义事件,并将需要传递的数据作为参数传入。
    • <script setup> 中,需先从 vue 导入 defineEmits 定义事件。
  2. 父组件:在使用子组件时,通过 @自定义事件名 监听事件,并在事件处理函数中接收子组件传递的数据。

示例1:基础用法(点击按钮传递数据)

子组件(Child.vue)
<template>
  <!-- 点击按钮时触发事件,传递数据 -->
  <button @click="sendData">向父组件传递数据</button>
</template>

<script setup>
// 定义子组件可触发的事件("send-message" 为自定义事件名)
const emit = defineEmits(['send-message'])

// 子组件的方法:触发事件并携带数据
const sendData = () => {
  const message = "我是子组件传递的数据"
  // 触发事件,第一个参数是事件名,第二个参数是要传递的数据
  emit('send-message', message)
}
</script>
父组件(Parent.vue)
<template>
  <div>
    <!-- 监听子组件的 "send-message" 事件,并用 handleMessage 处理 -->
    <Child @send-message="handleMessage" />
    <!-- 显示子组件传递的数据 -->
    <p>父组件接收的数据:{{ receivedData }}</p>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import Child from './Child.vue'

// 父组件存储接收的数据
const receivedData = ref('')

// 处理子组件传递的数据
const handleMessage = (data) => {
  receivedData.value = data // 将子组件数据赋值给父组件变量
}
</script>

示例2:实时传递输入框数据

更常见的场景是子组件实时传递用户输入(如表单),父组件实时响应。

子组件(InputChild.vue)
<template>
  <!-- 输入框变化时触发事件 -->
  <input 
    type="text" 
    v-model="inputValue" 
    @input="handleInput"
    placeholder="输入内容传递给父组件"
  >
</template>

<script setup>
import { ref } from 'vue'

// 定义可触发的事件
const emit = defineEmits(['input-change'])

// 子组件的输入值
const inputValue = ref('')

// 输入变化时触发事件,传递最新值
const handleInput = () => {
  emit('input-change', inputValue.value)
}
</script>
父组件(InputParent.vue)
<template>
  <div>
    <InputChild @input-change="handleInputChange" />
    <p>父组件实时显示:{{ inputData }}</p>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import InputChild from './InputChild.vue'

const inputData = ref('')

// 实时接收子组件的输入值
const handleInputChange = (value) => {
  inputData.value = value
}
</script>

示例3:使用v-model简化(双向绑定)

如果需要实现“子组件修改数据,父组件同步更新”的双向绑定效果,可以利用 v-model 语法糖(本质仍是自定义事件)。

子组件(VModelChild.vue)
<template>
  <input 
    type="text" 
    :value="modelValue" 
    @input="$emit('update:modelValue', $event.target.value)"
  >
</template>

<script setup>
// 接收父组件通过v-model传递的默认值
defineProps(['modelValue'])
// 声明更新事件(固定格式:update:modelValue)
defineEmits(['update:modelValue'])
</script>
父组件(VModelParent.vue)
<template>
  <div>
    <!-- 用v-model绑定,等价于 @update:modelValue="value = $event" -->
    <VModelChild v-model="parentValue" />
    <p>v-model绑定的值:{{ parentValue }}</p>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import VModelChild from './VModelChild.vue'

const parentValue = ref('初始值')
</script>

核心总结

  • 子传父的核心是 “子组件emit事件,父组件监听事件”
  • <script setup> 中需通过 defineEmits 声明事件,确保类型约束和代码可读性。
  • 复杂场景(如多层级组件)可考虑Vuex/Pinia或provide/inject,但父子直接通信优先使用自定义事件。
Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐