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是最佳选择。

相关推荐
weixin_382395238 小时前
为小工厂量身打造:本地部署的物料管理系统带缺料计算
前端·制造
__zRainy__8 小时前
解决pnpm v10+不自动构建
前端·pnpm·工程化
猫猫不是喵喵.8 小时前
Vue3 Props 属性
前端·javascript·vue.js
醉城夜风~9 小时前
CSS元素显示模式(display)
前端·css
AI大模型-小华10 小时前
Codex 三方充值快速入门指南
java·前端·数据库·chatgpt·ai编程·codex·chatgpt pro
做前端的娜娜子12 小时前
同一链接实现 PC Web 与移动 H5 自适应
前端·掘金·金石计划
小帅不太帅13 小时前
架构没变、规模没变,DeepSeek V4 Flash 正式版凭什么暴涨 47 分?
前端·aigc·deepseek
jarvisuni13 小时前
DeepSeekFlash前端依旧拉垮,而且变慢了很多!
前端·javascript·算法
卷福同学14 小时前
AI编程出海第二步:验证关键词能否做站
前端·人工智能·后端