Vue组件通信

Vue 组件通信是构建复杂应用的基础,以下是 Vue 2 和 Vue 3 中所有主要的组件通信方式及其适用场景:

一、父子组件通信

1. Props(父 → 子)

vue 复制代码
<!-- 父组件 -->
<ChildComponent :title="pageTitle" :user="userData" />

<!-- 子组件 -->
<script>
export default {
  props: {
    title: String,
    user: {
      type: Object,
      default: () => ({})
    }
  }
}
</script>

特点:单向数据流,适合父向子传值

2. $emit / 自定义事件(子 → 父)

vue

复制

xml 复制代码
<!-- 子组件 -->
<button @click="$emit('update', newValue)">提交</button>

<!-- 父组件 -->
<ChildComponent @update="handleUpdate" />

特点:子组件触发父组件方法

3. v-model(双向绑定)

vue 复制代码
<!-- Vue 3 默认方式 -->
<CustomInput v-model="searchText" />

<!-- 子组件实现 -->
<input :value="modelValue" @input="$emit('update:modelValue', $event.target.value)" />
<script>
export default {
  props: ['modelValue'],
  emits: ['update:modelValue']
}
</script>

二、跨层级组件通信

4. Provide / Inject(依赖注入)

javascript 复制代码
// 祖先组件 (Vue 3)
import { provide } from 'vue'
export default {
  setup() {
    provide('theme', 'dark')
  }
}

// 后代组件
import { inject } from 'vue'
export default {
  setup() {
    const theme = inject('theme', 'light') // 默认值
    return { theme }
  }
}

特点:适合深层嵌套组件通信

5. 事件总线(Event Bus)

javascript 复制代码
// Vue 3 需要外部库(如 mitt)
// bus.js
import mitt from 'mitt'
export default mitt()

// 组件A(发送)
import bus from './bus'
bus.emit('event-name', data)

// 组件B(接收)
bus.on('event-name', data => { ... })

// 记得在组件卸载时移除监听
onUnmounted(() => {
  bus.off('event-name')
})

特点:任意组件间通信,但需注意内存泄漏

三、状态管理方案

6. Vuex(Vue 2 官方状态管理)

javascript 复制代码
// store.js
import { createStore } from 'vuex'

export default createStore({
  state: { count: 0 },
  mutations: {
    increment(state) {
      state.count++
    }
  },
  actions: {
    incrementAsync({ commit }) {
      setTimeout(() => commit('increment'), 1000)
    }
  }
})

// 组件中使用
import { useStore } from 'vuex'
export default {
  setup() {
    const store = useStore()
    return {
      count: computed(() => store.state.count),
      increment: () => store.commit('increment')
    }
  }
}

7. Pinia(Vue 3 推荐状态管理)

javascript 复制代码
// stores/counter.js
import { defineStore } from 'pinia'

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

// 组件中使用
import { useCounterStore } from '@/stores/counter'
export default {
  setup() {
    const counter = useCounterStore()
    return { counter }
  }
}

特点:更简单、类型安全、组合式API友好

四、模板引用通信

8. ref / $refs

vue 复制代码
<!-- 父组件 -->
<ChildComponent ref="child" />

<script>
export default {
  mounted() {
    this.$refs.child.methodName() // 调用子组件方法
    this.$refs.child.property = value // 访问子组件属性
  }
}
</script>

特点:直接访问组件实例,但应谨慎使用

五、其他通信方式

9. attrs/attrs/listeners(Vue 2)

vue 复制代码
<!-- 父组件 -->
<ChildComponent v-bind="$attrs" v-on="$listeners" />

<!-- Vue 3 中已合并到 $attrs -->

10. parent/parent/children

javascript 复制代码
// 子组件中
this.$parent.methodName()

// 父组件中
this.$children[0].property = value

特点:不推荐使用,破坏组件封装性

11. 全局状态(不推荐)

javascript 复制代码
// main.js
app.config.globalProperties.$appName = 'My App'

// 组件中
this.$appName

六、通信方式选择指南

通信方式 适用场景 Vue 2 Vue 3 备注
Props 父→子数据传递 推荐首选
$emit 子→父事件通知 推荐首选
v-model 表单双向绑定 语法糖
Provide/Inject 跨层级传递 适合主题/配置
事件总线 任意组件通信 ⚠️需库 注意内存泄漏
Vuex 复杂状态管理 ⚠️兼容 Vue 2首选
Pinia 现代状态管理 Vue 3首选
$refs 直接访问组件 应急方案
$attrs 属性透传 高阶组件
$parent 访问父实例 不推荐

最佳实践建议

  1. 简单场景:优先使用 props + emit
  2. 兄弟组件:提升状态到共同父级或使用状态管理
  3. 跨层级:使用 Provide/Inject 或状态管理
  4. 全局状态:使用 Pinia/Vuex
  5. 避免:直接修改子组件状态($refs)、过度使用事件总线
  6. TypeScript:为所有通信方式添加类型定义

Vue 3 组合式API通信示例

javascript 复制代码
// useCounter.js - 可组合函数
import { ref } from 'vue'

export function useCounter() {
  const count = ref(0)
  const increment = () => count.value++
  
  return { count, increment }
}

// 组件A
import { useCounter } from './useCounter'
const { count, increment } = useCounter()

// 组件B
import { useCounter } from './useCounter'
const { count } = useCounter() // 共享状态

选择通信方式时应考虑组件关系、数据流清晰度和长期维护成本。对于新项目,Vue 3 + Pinia + 组合式API是最佳选择。

相关推荐
aiprtem20 分钟前
基于Flutter的web登录设计
前端·flutter
浪裡遊23 分钟前
React Hooks全面解析:从基础到高级的实用指南
开发语言·前端·javascript·react.js·node.js·ecmascript·php
why技术30 分钟前
Stack Overflow,轰然倒下!
前端·人工智能·后端
幽络源小助理34 分钟前
SpringBoot基于Mysql的商业辅助决策系统设计与实现
java·vue.js·spring boot·后端·mysql·spring
GISer_Jing35 分钟前
0704-0706上海,又聚上了
前端·新浪微博
止观止1 小时前
深入探索 pnpm:高效磁盘利用与灵活的包管理解决方案
前端·pnpm·前端工程化·包管理器
whale fall1 小时前
npm install安装的node_modules是什么
前端·npm·node.js
烛阴1 小时前
简单入门Python装饰器
前端·python
袁煦丞2 小时前
数据库设计神器DrawDB:cpolar内网穿透实验室第595个成功挑战
前端·程序员·远程工作
天天扭码2 小时前
从图片到语音:我是如何用两大模型API打造沉浸式英语学习工具的
前端·人工智能·github