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. 事件总线仅适用于简单场景,中大型项目慎用
相关推荐
爱编程的喵几秒前
深入理解JavaScript节流函数:从原理到实战应用
前端·javascript·html
尧木晓晓1 分钟前
开发避坑指南:Whistle 代理失效背后,localhost和 127.0.0.1 的 “爱恨情仇” 与终极解决方案
前端·javascript
风无雨33 分钟前
GO启动一个视频下载接口 前端可以边下边放
前端·golang·音视频
Rainbow_Pearl38 分钟前
Vue2_element 表头查询功能
javascript·vue.js·elementui
aha-凯心1 小时前
前端学习 vben 之 axios interceptors
前端·学习
熊出没2 小时前
Vue前端导出页面为PDF文件
前端·vue.js·pdf
VOLUN2 小时前
Vue3项目中优雅封装API基础接口:getBaseApi设计解析
前端·vue.js·api
用户99045017780092 小时前
告别广告干扰,体验极简 JSON 格式化——这款工具让你专注代码本身
前端
前端极客探险家2 小时前
告别卡顿与慢响应!现代 Web 应用性能优化:从前端渲染到后端算法的全面提速指南
前端·算法·性能优化
袁煦丞3 小时前
【局域网秒传神器】LocalSend:cpolar内网穿透实验室第418个成功挑战
前端·程序员·远程工作