Vue中组件通信的8种实现方法与对比的完整指南

 更新时间:2025年10月30日 09:34:36   作者:良山有风来  
选择正确的通信方式,能让你的应用像高效运转的团队一样协作顺畅,本文就把Vue组件通信的8种神操作一次性讲清楚,每种方法都有适用场景和代码示例,下面就跟随小编一起深入了解下吧

你是不是遇到过这种情况?一个数据要从爷爷组件传给孙子组件,结果props一层层往下传,写得手都酸了?

或者两个毫无关系的组件要交换数据,只能把数据提升到公共祖先,搞得整个项目数据流乱成一团麻?

别担心!今天我就把Vue组件通信的8种神操作一次性讲清楚,每种方法都有适用场景和代码示例,看完保证你不再为组件通信头疼!

1. 最基础的父子对话:props/$emit

这是Vue中最经典的父子组件通信方式,就像爸爸对儿子说:"这个数据给你用",儿子完成后告诉爸爸:"我搞定了"。

// 父组件
<template>
  <child-component 
    :message="parentMessage" 
    @child-clicked="handleChildClick"
  />
</template>

<script>
export default {
  data() {
    return {
      parentMessage: '这是爸爸给你的数据'
    }
  },
  methods: {
    handleChildClick(data) {
      console.log('儿子告诉我:', data)
    }
  }
}
</script>

// 子组件
<template>
  <button @click="sendToParent">点击告诉爸爸</button>
</template>

<script>
export default {
  props: ['message'], // 接收爸爸给的数据
  methods: {
    sendToParent() {
      this.$emit('child-clicked', '爸爸,我完成任务了!')
    }
  }
}
</script>

适用场景:直接的父子组件通信,简单明了。但如果层级太深,就会变成"钻山洞",写起来很麻烦。

2. 属性透传神器:attrs &listeners

有时候我们想要一个"中间人"组件,它只是过一下手,不处理数据。这时候就用上attrs和attrs和attrslisteners了。

Vue 2和Vue 3用法有点不同,我们先看Vue 2的:

// 爷爷组件
<parent-component :title="标题" :content="内容" @custom-event="handleEvent"/>

// 父组件(中间人)
<template>
  <child-component v-bind="$attrs" v-on="$listeners"/>
</template>

<script>
export default {
  // 注意:这里不声明props,$attrs会自动包含所有未声明的属性
}
</script>

// 子组件(最终接收者)
export default {
  props: ['title', 'content'], // 直接接收爷爷传来的属性
  mounted() {
    this.$emit('custom-event') // 直接触发爷爷的事件
  }
}

Vue 3更简单了,直接用v-bind:

// 中间组件
<child-component v-bind="$attrs"/>

适用场景:创建高阶组件或包装组件时特别有用,避免在中间组件中重复声明props和events。

3. 直接找亲戚:parent/parent/parent/children/$refs

有时候规矩太多很麻烦,直接"上门找人"更直接:

// 父组件
<template>
  <child-component ref="myChild"/>
  <button @click="callChildMethod">调用子组件方法</button>
</template>

<script>
export default {
  methods: {
    callChildMethod() {
      // 通过ref直接调用子组件方法
      this.$refs.myChild.doSomething()
      
      // 或者通过$children(不常用,因为顺序可能变化)
      this.$children[0].doSomething()
    }
  }
}
</script>

// 子组件
<script>
export default {
  methods: {
    doSomething() {
      // 直接找父组件
      this.$parent.parentMethod()
    }
  }
}
</script>

适用场景:简单项目或小组件中使用,但不推荐在复杂项目中使用,因为组件关系太紧密,不易维护。

4. 隔代传数据:Provide/Inject

爷爷想直接给孙子东西,不想经过爸爸中转?Provide/Inject就是为这种场景设计的:

// 爷爷组件
<script>
export default {
  provide() {
    return {
      grandpaData: '这是爷爷给的数据',
      grandpaMethod: this.someMethod
    }
  },
  methods: {
    someMethod() {
      console.log('爷爷的方法被调用了')
    }
  }
}
</script>

// 孙子组件(跳过父组件)
<script>
export default {
  inject: ['grandpaData', 'grandpaMethod'],
  mounted() {
    console.log(this.grandpaData) // 直接使用爷爷的数据
    this.grandpaMethod() // 直接调用爷爷的方法
  }
}
</script>

适用场景:深层嵌套组件通信,尤其是组件库开发时特别有用。

5. 全局事件巴士:Event Bus

两个毫无关系的组件要通信怎么办?建一个"全局事件巴士"!

// event-bus.js
import Vue from 'vue'
export const EventBus = new Vue()

// 组件A(发送事件)
<script>
import { EventBus } from './event-bus.js'

export default {
  methods: {
    sendMessage() {
      EventBus.$emit('message-sent', '你好,另一个组件!')
    }
  }
}
</script>

// 组件B(接收事件)
<script>
import { EventBus } from './event-bus.js'

export default {
  mounted() {
    EventBus.$on('message-sent', (message) => {
      console.log('收到消息:', message)
    })
  },
  // 记得在组件销毁时移除监听,避免内存泄漏
  beforeDestroy() {
    EventBus.$off('message-sent')
  }
}
</script>

适用场景:非父子组件通信,简单项目中的跨组件通信。但项目复杂后容易变得混乱,需要谨慎使用。

6. 状态管理之王:Vuex

当项目变得复杂,多个组件需要共享状态时,Vuex就是你的救星:

// store.js
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    count: 0,
    user: null
  },
  mutations: {
    // 同步修改状态
    increment(state) {
      state.count++
    },
    setUser(state, user) {
      state.user = user
    }
  },
  actions: {
    // 异步操作
    async fetchUser({ commit }) {
      const user = await api.getUser()
      commit('setUser', user)
    }
  },
  getters: {
    // 计算属性
    doubleCount: state => state.count * 2
  }
})

// 组件中使用
<script>
export default {
  computed: {
    count() {
      return this.$store.state.count
    },
    doubleCount() {
      return this.$store.getters.doubleCount
    }
  },
  methods: {
    increment() {
      this.$store.commit('increment')
    },
    fetchUser() {
      this.$store.dispatch('fetchUser')
    }
  }
}
</script>

适用场景:中大型项目,多个组件需要共享状态,需要跟踪状态变化。

7. 现代状态管理:Pinia

Pinia是Vue官方推荐的新一代状态管理库,比Vuex更简单、更灵活:

// stores/counter.js
import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', {
  state: () => ({ count: 0 }),
  getters: {
    doubleCount: (state) => state.count * 2,
  },
  actions: {
    increment() {
      this.count++
    },
  },
})

// 组件中使用
<script setup>
import { useCounterStore } from '@/stores/counter'

const counter = useCounterStore()

// 直接访问和修改状态(Pinia会自动处理)
counter.count++
counter.increment()

// 使用计算属性
const doubleValue = computed(() => counter.doubleCount)
</script>

适用场景:新项目首选,TypeScript支持更好,API更简洁,学习成本更低。

8. 终极方案:Vue 3的响应式API

Vue 3的reactivity API可以让你自己创建响应式对象,实现灵活的组件通信:

// shared-state.js
import { reactive } from 'vue'

export const sharedState = reactive({
  message: '',
  updateMessage(newMessage) {
    this.message = newMessage
  }
})

// 组件A
<script setup>
import { sharedState } from './shared-state'

const updateSharedMessage = () => {
  sharedState.updateMessage('来自组件A的消息')
}
</script>

// 组件B
<script setup>
import { sharedState } from './shared-state'
import { watch } from 'vue'

// 监听共享状态的变化
watch(() => sharedState.message, (newMessage) => {
  console.log('消息更新了:', newMessage)
})
</script>

适用场景:需要轻量级状态共享,不想引入Vuex或Pinia的小型项目。

怎么选择?看这里!

这么多方法,到底用哪个?我给你个简单指南:

  • 父子组件简单通信:props/$emit
  • 属性透传:$attrs
  • 隔代传数据:Provide/Inject
  • 简单项目跨组件通信:Event Bus
  • 中大型项目状态管理:Vuex或Pinia
  • 轻量级共享:Vue 3 reactive API

记住,没有最好的方案,只有最适合的方案。简单场景用简单方法,复杂场景再用复杂方案,不要为了用而用。

最后说两句

组件通信是Vue开发中的核心技能,掌握这些方法能让你在开发中游刃有余。但也要注意,不要过度设计,能用简单方法解决的问题,就不要用复杂方案。

以上就是Vue中组件通信的8种实现方法与对比的完整指南的详细内容,更多关于Vue组件通信的资料请关注脚本之家其它相关文章!

相关文章

  • 浅析Vue实例以及生命周期

    浅析Vue实例以及生命周期

    这篇文章给大家分享了Vue实例以及生命周期的相关知识点内容,有兴趣的朋友们可以学习下。
    2018-08-08
  • vue下canvas裁剪图片实例讲解

    vue下canvas裁剪图片实例讲解

    在本篇文章里小编给大家整理了关于vue下canvas裁剪图片实例讲解内容,需要的朋友们可以参考下。
    2020-04-04
  • vue 录制视频并压缩视频文件的方法

    vue 录制视频并压缩视频文件的方法

    这篇文章主要介绍了vue 录制视频并压缩视频文件的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-07-07
  • 详解Vue计算属性原理

    详解Vue计算属性原理

    计算属性是Vue中比较好用的API,开发者可以利用计算属将复杂的计算进行缓存,同时基于它的响应式特性,我们无需关注数据更新问题,但需要注意的是,计算属性是惰性求值的,本文将详细介绍计算属性的实现原理,需要的朋友可以参考下
    2023-05-05
  • Vue+Element UI+vue-quill-editor富文本编辑器及插入图片自定义

    Vue+Element UI+vue-quill-editor富文本编辑器及插入图片自定义

    这篇文章主要为大家详细介绍了Vue+Element UI+vue-quill-editor富文本编辑器及插入图片自定义,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-08-08
  • vue3.0+echarts实现立体柱图

    vue3.0+echarts实现立体柱图

    这篇文章主要为大家详细介绍了vue3.0+echarts实现立体柱图,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-09-09
  • 基于Vue-Cli 打包自动生成/抽离相关配置文件的实现方法

    基于Vue-Cli 打包自动生成/抽离相关配置文件的实现方法

    基于Vue-cli 项目产品部署,涉及到的交互的地址等配置信息,每次都要重新打包才能生效,极大的降低了效率。这篇文章主要介绍了基于Vue-Cli 打包自动生成/抽离相关配置文件 ,需要的朋友可以参考下
    2018-12-12
  • webpack&webpack-cli完全卸载过程

    webpack&webpack-cli完全卸载过程

    本文介绍了如何删除全局和本地的webpack及其CLI,并提供了检查webpack残余文件的方法,总结了个人的操作经验,旨在为读者提供参考,并期待获得更多支持
    2024-09-09
  • vue 自定义右键样式的实例代码

    vue 自定义右键样式的实例代码

    这篇文章主要介绍了vue 自定义右键样式的实例代码,代码简单易懂,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-11-11
  • vue中的事件修饰符once,prevent,stop,capture,self,passive

    vue中的事件修饰符once,prevent,stop,capture,self,passive

    这篇文章主要介绍了vue中的事件修饰符once,prevent,stop,capture,self,passive,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-04-04

最新评论