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. 事件总线仅适用于简单场景,中大型项目慎用
相关推荐
Liu.77420 分钟前
vue3使用vue3-print-nb打印
前端·javascript·vue.js
松涛和鸣1 小时前
Linux Makefile : From Basic Syntax to Multi-File Project Compilation
linux·运维·服务器·前端·windows·哈希算法
dly_blog1 小时前
Vue 逻辑复用的多种方案对比!
前端·javascript·vue.js
万少2 小时前
HarmonyOS6 接入分享,原来也是三分钟的事情
前端·harmonyos
烛阴2 小时前
C# 正则表达式:量词与锚点——从“.*”到精确匹配
前端·正则表达式·c#
wyzqhhhh2 小时前
京东啊啊啊啊啊
开发语言·前端·javascript
JIngJaneIL2 小时前
基于java+ vue助农电商系统(源码+数据库+文档)
java·开发语言·前端·数据库·vue.js·spring boot·后端
q_19132846952 小时前
基于Springboot+MySQL+RuoYi的会议室预约管理系统
java·vue.js·spring boot·后端·mysql·若依·计算机毕业设计
想学后端的前端工程师2 小时前
【Java集合框架深度解析:从入门到精通-后端技术栈】
前端·javascript·vue.js
VcB之殇2 小时前
git常用操作合集
前端·git