Vue3父子组件通信示例

以下是一个完整的Vue3父子组件通信示例,包含参数传递、事件触发和方法调用:

父组件 ParentComponent.vue

<template>
  <div class="parent-container">
    <h2>父组件</h2>
    <ChildComponent 
      :title="childTitle"
      :user-data="user"
      :item-list="items"
      @update-title="handleTitleUpdate"
      @submit-data="handleDataSubmit"
      ref="childComponentRef"
    >
      <template #default>
        <p>这是插槽内容</p>
      </template>
    </ChildComponent>

    <button @click="callChildMethod">调用子组件方法</button>
  </div>
</template>

<script setup>
import { ref, reactive } from 'vue'
import ChildComponent from './ChildComponent.vue'

// 子组件引用(不明白的可以参考 https://www.cnblogs.com/smile-fanyin/p/18772074
const childComponentRef = ref(null)  

// 传递给子组件的props数据
const childTitle = ref('初始标题')
const user = reactive({
  name: '张三',
  age: 25,
  email: 'zhangsan@example.com'
})
const items = ref(['苹果', '香蕉', '橙子'])

// 处理子组件事件
const handleTitleUpdate = (newTitle) => {
  console.log('接收到子组件的新标题:', newTitle)
  childTitle.value = newTitle
}

const handleDataSubmit = (formData) => {
  console.log('接收到子组件提交的数据:', formData)
  // 这里可以处理数据提交逻辑
}

// 调用子组件暴露的方法
const callChildMethod = () => {
  if (childComponentRef.value) {
    childComponentRef.value.resetForm()
  }
}
</script>

<style scoped>
.parent-container {
  padding: 20px;
  border: 2px solid #3498db;
  margin: 20px;
}
</style>

子组件 ChildComponent.vue

<template>
  <div class="child-container">
    <h3>子组件 - {{ title }}</h3>
    
    <!-- 显示props数据 -->
    <p>用户信息:{{ userData.name }} ({{ userData.age }})</p>
    <ul>
      <li v-for="(item, index) in itemList" :key="index">
        {{ item }}
      </li>
    </ul>

    <!-- 表单示例 -->
    <form @submit.prevent="submitForm">
      <input v-model="localTitle" type="text">
      <button type="submit">更新标题</button>
    </form>

    <!-- 插槽 -->
    <slot></slot>
  </div>
</template>

<script setup>
import { ref, defineProps, defineEmits, watch } from 'vue'

// 定义props
const props = defineProps({
  title: {
    type: String,
    default: '默认标题'
  },
  userData: {
    type: Object,
    default: () => ({})
  },
  itemList: {
    type: Array,
    default: () => []
  }
})

// 定义事件
const emit = defineEmits(['update-title', 'submit-data'])

// 本地数据
const localTitle = ref(props.title)

// 监听props变化
watch(() => props.title, (newVal) => {
  localTitle.value = newVal
})

// 表单提交方法
const submitForm = () => {
  emit('update-title', localTitle.value)
  emit('submit-data', {
    newTitle: localTitle.value,
    timestamp: new Date().toISOString()
  })
}

// 暴露给父组件的方法
const resetForm = () => {
  localTitle.value = props.title
  console.log('表单已重置')
}

// 暴露方法
defineExpose({
  resetForm
})
</script>

<style scoped>
.child-container {
  padding: 15px;
  border: 1px solid #e74c3c;
  margin: 10px 0;
}

input {
  margin: 10px;
  padding: 5px;
}
</style>

主要通信方式说明:

  1. Props 传参

    • 父组件通过 :propName="value" 传递数据

    • 子组件使用 defineProps 接收

    • 支持类型检查、默认值和复杂对象

  2. 自定义事件

    • 子组件通过 defineEmits 定义事件

    • 使用 emit('eventName', payload) 触发事件

    • 父组件通过 @eventName="handler" 监听

  3. 组件引用

    • 父组件使用 ref 获取子组件实例

    • 子组件通过 defineExpose 暴露方法

    • 父组件可以调用子组件暴露的方法

  4. 双向绑定

    • 可以通过 v-model 实现(Vue3支持多个v-model)

    • 或通过 props + 事件组合实现

  5. 插槽通信

    • 父组件通过 <template #slotName> 传递内容

    • 子组件通过 <slot> 接收内容

使用场景示例:

  • 父组件传递初始配置数据(props)

  • 子组件提交表单数据(自定义事件)

  • 父组件重置子组件状态(暴露方法)

  • 动态更新标题(双向数据流)

  • 内容定制(插槽)

注意事项:

  1. 始终使用 defineProps 和 defineEmits 进行类型定义

  2. 复杂对象的默认值应该使用工厂函数返回

  3. 避免直接修改props,使用本地数据副本

  4. 事件命名建议使用kebab-case(update-title)

  5. 暴露方法时注意组件封装性,只暴露必要接口

这个示例展示了Vue3中最常用的父子组件通信方式,可以根据具体需求组合使用这些方法来实现各种组件交互场景。

 

posted @ 2025-03-14 14:26  smil、梵音  阅读(646)  评论(0)    收藏  举报