Vue 组件通信详解

以下是 Vue 组件通信的三种核心方式及详细实现方案,适用于 Vue 2/3 版本:


1. 父子组件通信

核心方法:Props 向下传递,Events 向上传递

vue 复制代码
<!-- 父组件 Parent.vue -->
<template>
  <Child 
    :title="parentData" 
    @child-event="handleEvent"
  />
</template>

<script>
export default {
  data() {
    return { parentData: "来自父组件的数据" }
  },
  methods: {
    handleEvent(payload) {
      console.log("子组件传值:", payload) // 接收子组件数据
    }
  }
}
</script>

<!-- 子组件 Child.vue -->
<template>
  <div>
    <h2>{{ title }}</h2> <!-- 接收父组件数据 -->
    <button @click="sendToParent">传递数据</button>
  </div>
</template>

<script>
export default {
  props: ['title'], // 声明接收的prop
  methods: {
    sendToParent() {
      this.$emit('child-event', { data: "子组件数据" }) // 触发自定义事件
    }
  }
}
</script>

关键点:

  • Prop 验证 (Vue 2/3 通用):

    js 复制代码
    props: {
      title: {
        type: String,
        required: true,
        default: "默认标题"
      }
    }
  • Vue 3 特有 :使用 definePropsdefineEmits 编译器宏(<script setup>

    vue 复制代码
    <script setup>
    const props = defineProps(['title'])
    const emit = defineEmits(['child-event'])
    emit('child-event', { data: "子组件数据" })
    </script>

2. 插槽(Slots)

用于内容分发,支持模板级通信

vue 复制代码
<!-- 父组件 -->
<Child>
  <!-- 默认插槽 -->
  <template>默认插入内容</template>
  
  <!-- 具名插槽 -->
  <template v-slot:header>
    <h1>标题插槽</h1>
  </template>
  
  <!-- 作用域插槽(接收子组件数据) -->
  <template v-slot:footer="slotProps">
    <p>来自子组件的数据: {{ slotProps.childData }}</p>
  </template>
</Child>

<!-- 子组件 Child.vue -->
<template>
  <div>
    <slot name="header"></slot> <!-- 具名插槽 -->
    <slot></slot> <!-- 默认插槽 -->
    <slot name="footer" :childData="dataForParent"></slot> <!-- 作用域插槽 -->
  </div>
</template>

<script>
export default {
  data() {
    return { dataForParent: "子组件传递的数据" }
  }
}
</script>

关键点:

  • 动态插槽名<template v-slot:[dynamicSlotName]>
  • 缩写语法#header 等价于 v-slot:header
  • 作用域插槽是子组件向父组件模板传递数据的唯一方式

3. 非父子组件通信

方案 1:事件总线(Event Bus)
js 复制代码
// eventBus.js (Vue 2)
import Vue from 'vue'
export default new Vue()

// 组件A(发送事件)
import eventBus from './eventBus'
eventBus.$emit('global-event', { data: "跨组件数据" })

// 组件B(接收事件)
eventBus.$on('global-event', payload => {
  console.log("收到数据:", payload)
})

Vue 3 替代方案(推荐使用 mitt 库):

bash 复制代码
npm install mitt
js 复制代码
// eventBus.js
import mitt from 'mitt'
export default mitt()

// 使用方式相同(取消 .$ 前缀)
eventBus.emit('event')
eventBus.on('event', callback)
方案 2:Provide / Inject(依赖注入)
vue 复制代码
<!-- 祖先组件 -->
<script>
export default {
  provide() {
    return {
      sharedData: "全局数据",
      sharedMethod: this.doSomething // 传递方法
    }
  },
  methods: {
    doSomething() { console.log("跨组件调用") }
  }
}
</script>

<!-- 后代组件(任意层级) -->
<script>
export default {
  inject: ['sharedData', 'sharedMethod'],
  mounted() {
    console.log(this.sharedData) // "全局数据"
    this.sharedMethod()          // 调用祖先方法
  }
}
</script>

Vue 3 增强:

vue 复制代码
<!-- 祖先组件(Composition API) -->
<script setup>
import { provide, ref } from 'vue'
const counter = ref(0)
provide('counter', counter) // 提供响应式数据
</script>

<!-- 后代组件 -->
<script setup>
import { inject } from 'vue'
const counter = inject('counter')
</script>
方案 3:状态管理库(Vuex / Pinia)
js 复制代码
// Pinia 示例 (Vue 3 推荐)
// store/counter.js
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', {
  state: () => ({ count: 0 }),
  actions: {
    increment() { this.count++ }
  }
})

// 任意组件中使用
import { useCounterStore } from '@/store/counter'
const store = useCounterStore()
console.log(store.count) // 获取状态
store.increment()       // 触发动作

通信方案对比

方式 适用场景 数据流向 复杂度
Props/Events 直接父子组件 双向
Slots 内容分发+模板数据传递 子→父(模板) ⭐⭐
Event Bus 简单跨组件通信(小型应用) 任意方向 ⭐⭐
Provide/Inject 深层嵌套组件 祖先→后代 ⭐⭐⭐
Vuex/Pinia 中大型应用状态管理 集中式 ⭐⭐⭐⭐

最佳实践建议

  1. 优先使用 Props/Events 处理直接父子通信
  2. 深层组件用 Provide/Inject 替代多级 prop 传递
  3. 全局状态管理首选 Pinia (Vue 3) 或 Vuex
  4. 事件总线仅适用于简单场景,中大型项目慎用
相关推荐
在钱塘江2 分钟前
《你不知道的JavaScript-上卷》-笔记-5-作用域闭包
前端
搬砖码3 分钟前
Vue病历写回功能:实现多输入框内容插入与焦点管理🚀
前端
不简说7 分钟前
史诗级更新!sv-print虽然不是很强,但却是很能打的设计器组件
前端·产品
用户95251151401558 分钟前
最常用的JS加解密场景MD5
前端
Hilaku9 分钟前
“虚拟DOM”到底是什么?我们用300行代码来实现一个
前端·javascript·vue.js
打好高远球15 分钟前
mo契官网建设与SEO实践
前端
神仙别闹20 分钟前
基于Java+MySQL实现(Web)可扩展的程序在线评测系统
java·前端·mysql
心.c35 分钟前
react当中的this指向
前端·javascript·react.js
Java水解42 分钟前
Web API基础
前端
闲鱼不闲43 分钟前
实现iframe重定向通知父级页面跳转
前端