当前位置: 首页 > news >正文

vue组件间通信

在Vue中,组件间通信是开发复杂应用的核心问题。根据组件关系(父子、兄弟、跨级、全局)的不同,通信方式也有所区别。以下是Vue组件间通信的8种常用方式。

一、父子组件通信

  1. Props(父->子)
  • 父组件通过props向子组件传递数据。
<!-- 父组件 -->
<Child :title="parentTitle" /><!-- 子组件 -->
<script>
export default {props: ['title'] // 接收数据
}
</script>

注意:Props是单向数据流,子组件不能直接修改。
2. $emit/v-on(子->父)

  • 子组件通过$emit触发事件,父组件通过v-on监听。
<!-- 父组件 -->
<Child @update="handleUpdate" /><!-- 子组件 -->
<button @click="$emit('update', newValue)">提交</button>

二、兄弟组件通信

  1. 共同父组件(Event Bus 模式)
  • 通过共同的父组件作为中介:
// 父组件
<ChildA @event="handleEvent" />
<ChildB :data="sharedData" />// ChildA 触发事件
this.$emit('event', data)// 父组件讲数据传递给 ChildB 
  1. Event Bus(全局事件总线)
    Event Bus是一种发布-订阅模式的通信方式,适用于任意组件间通信(父子、兄弟、跨级),无需依赖共同的父组件或Vuex/Pinia。
  • 创建Event Bus
    首先,创建一个全局的Vue实例作为事件中心(通常在bus.js文件中定义):
// src/utils/bus.js
import Vue from 'vue';
export const bus = new Vue(); // 导出一个Vue实例
  • 发送事件( e m i t )在需要发送数据的组件中,使用 ‘ b u s . emit) 在需要发送数据的组件中,使用`bus. emit)在需要发送数据的组件中,使用bus.emit('事件名‘,数据)`:
<!-- ComponentA.vue -->
<script>
import { bus } from '@utils/bus';
export default {methods: {sendMessage() {bus.$emit('message', 'Hello from ComponentA!');}}
}
</script><template><button @click="sendMessage">发送消息</button>
</template>
  • 监听事件( o n )在需要接收数据的组件中,使用 ‘ b u s . on) 在需要接收数据的组件中,使用`bus. on)在需要接收数据的组件中,使用bus.on(‘事件名’, callback)`监听事件:
<!-- ComponentB.vue -->
<script>
import { bus } from '@/utils/bus';
export default {created() {bus.$on('message', (data) => {console.log('收到消息:', data); // "Hello from ComponentA!"})},beforeDestroy() {// 组件销毁时,移除监听,避免内存泄漏bus.$off('message');}
}
</script>
  • 移除监听($off)
    为了避免内存泄漏,需要在组件销毁时移除监听:
beforeDestory() {bus.$off('message'); // 移除单个事件监听// bus.$off(); // 移除所有监听(慎用)
}
  • 完整示例
    场景:
    ComponentA 发送消息
    ComponentB 和 ComponentC 接收消息
    (1)bus.js
import Vue from 'vue';
export const bus = new Vue();

(2)ComponentA.vue(发送方)

<script>
import { bus } from '@/utils/bus';export default {methods: {sendData() {bus.$emit('update', { text: 'Hello Event Bus!' });}}
}
</script><template><button @click="sendData">发送数据</button>
</template>

(3)ComponentB.vue(接收方1)

<script>
import { bus } from '@/utils/bus';export default {data() {return {receivedData: null};},created() {bus.$on('update', (data) => {this.receivedData = data.text;});},beforeDestroy() {bus.$off('update');}
}
</script><template><div>收到数据: {{ receivedData }}</div>
</template>

(4)ComponentC.vue(接收方2)

<script>
import { bus } from '@/utils/bus';export default {created() {bus.$on('update', (data) => {alert(`ComponentC 收到: ${data.text}`);});},beforeDestroy() {bus.$off('update');}
}
</script>
  • 适用场景
    ✅ 任意组件间通信(父子、兄弟、跨级)
    ✅ 简单项目,不想引入 Vuex/Pinia
    ❌ 大型项目(建议用 Vuex/Pinia,Event Bus 难以维护)

  • 注意事项

  1. 内存泄漏:必须用 beforeDestroy 或 onUnmounted(Vue 3)移除监听。
  2. 调试困难:事件全局触发,难以追踪来源。
  3. 替代方案:
    Vue 2:Vue.observable(轻量状态管理)
    Vue 3:mitt(更小更快的 Event Bus 库)

三、跨级组件通信

  1. Provide/Inject
  • 祖先组件通过provide提供数据,后代组件通过inject注入:
// 祖先组件
export default {provide() {return { theme: 'dark' };}
}// 后代组件
export default {inject: ['theme'] // 直接适用this.theme
}

适用场景:深层嵌套组件(如 UI 库的主题配置)。

  1. attrs/listeners
    在Vue中,$attrs$listeners用于处理跨级组件通信透传属性和事件,特别适用于封装高阶组件(如自定义表单控件、UI组件库)。以下是详细示例和解析:
  • $attrs$listeners的作用
    $attrs:包含父组件传递的、未被props接收的非class/style属性,vue3中需v-bind="$attrs"
    $listeners:包含父组件传递的所有事件监听器(Vue2特有)

  • Vue2示例:透传属性和事件
    场景
    父组件–>中间组件–>子组件,透传placeholder属性和focus事件。
    (1) 父组件 (Parent.vue)

<template><MiddleComponent placeholder="请输入用户名" @focus="handleFocus" />
</template><script>
export default {methods: {handleFocus() {console.log("输入框获取焦点");}}
}
</script>

(2) 中间组件 (MiddleComponent.vue)

<template><!-- 透传所有属性和事件到子组件 --><ChildComponet v-bind="$attrs" v-on="$listeners" />
</template>
<script>
export default {// 不声明props,让$atts接收所有属性
}
</script>

(3) 子组件 (ChildComponent.vue)

<template><input :placeholder="$attrs.placeholder"  <!-- 直接使用 $attrs -->@focus="$listeners.focus"  <!-- 触发父组件事件 -->
</template>

关键点:
- 中间组件不声明props,让$attrs自动接收所有未声明的属性。
- 用v-bind="$attrs"v-on="$listeners"透传到子组件。

  • Vue3示例($attrs包含事件)
    Vue3删除了$listeners,所有事件也通过$attrs传递。
    (1) 父组件 (Parent.vue)
<template><MiddleComponentplaceholder="请输入密码"@focus="handleFocus"/>
</template>

(2) 中间组件 (MiddleComponent.vue)

<template><ChildComponent v-bind="$attrs" />
</template>

(3) 子组件 (ChildComponent.vue)

<template><input:placeholder="$attrs.placeholder"@focus="$attrs.onFocus"  <!-- Vue 3 事件名变为 onXxx -->/>
</template>

Vue3变化:

  1. 事件监听器在$attrs中以onXxx形式存在(如@focus->onFocus)。
  2. 不再需要 v-on="$listeners"
  • 高级用法:选择性透传
    如果中间组件需要拦截部分属性/事件,可以手动筛选:
    中间组件 (MiddleComponent.vue)
<template><ChildComponent :placeholder="$attrs.placeholder" @custom-event="handleCustomEvent"<!-- 只透传特定事件 -->v-on="filteredListeners"/>
</template>
<script>
export default {computed: {filteredListeners() {const { focus, ...rest } = this.$listeners; // 过滤掉 focus 事件return rest;}},methods: {handleCustomEvent() {console.log("拦截自定义事件");}}
}
</script>
  • 常见问题
    Q1: 为什么 $attrs 不包含 classstyle
  • Vue 默认将 classstyle 绑定到组件的根元素,如需透传需手动处理:
<ChildCompoent :class="$attrs.class" />

Q2: 如何避免属性重复绑定?

  • 如果子组件的根元素已经绑定了$attrs,可以用inheritAttrs: false禁止默认行为:
export default {inheritAttrs: false // 阻止自动绑定到根元素
}
  • 适用场景
  1. 封装表单控制(如自定义input): $attrs+$listeners
  2. 高阶组件(HOC): 透传所有未处理属性/事件
  3. UI组件库开发:避免属性丢失,保持灵活性
    总结:
  4. Vue 2:$attrs(属性) + $listeners(事件)分别透传。
  5. Vue 3:$attrs 包含属性和事件(事件名变为 onXxx)。
  6. 最佳实践:
    中间组件用 v-bind=“$attrs” 透传属性。
    用 inheritAttrs: false 避免重复绑定。
    需要拦截时手动筛选 $attrs 或 $listeners。

四、全局状态管理

  1. Vuex(官方状态管理)
  • 集中式存储管理所有组件的状态:
// store.js
export default new Vuex.Store({state: { count: 0 },mutations: {increment(state) { state.count++; }}
});// 组件中使用
this.$store.commit('increment');
console.log(this.$store.state.count);

适用场景:中大型应用,需要共享状态的复杂场景。

  1. Pinia(Vue 3 推荐)
  • Vuex的替代方案,更简洁的API:
// stores/counter.js
export const useCounterStore = defineStore('counter', {state: () => ({count: 0}),actions: {increment() { this.count++; }}
});// 组件中使用
const counter = useCounterStore();
counter.increment();

五、其他方式

  • $refs: 直接访问子组件实例(禁耦合,慎用)。
  • LocalStorage/SesstionStorage: 持久化存储(非响应式,需手动监听)。
  • Vue3的setup+ defineExpose:暴露子组件方法。

选择通信方式的准则

  1. 父子组件:优先用 props + $emit。
  2. 兄弟组件:用共同的父组件或 Event Bus。
  3. 跨级组件:用 provide/inject 或 Vuex/Pinia。
  4. 全局状态:Vuex(Vue 2)或 Pinia(Vue 3)。
http://www.xdnf.cn/news/181009.html

相关文章:

  • 蓝桥杯 9.生命之树
  • 【Multipath】dm软链接相关问题定位
  • 前端高频面试题day3
  • Python装饰器:函数增强的秘密武器
  • 使用ZXing开发安卓扫码功能
  • 【C++】C++11新特性(一)
  • 【前端】element表格X轴滚动优化拖拽滚动
  • 函数式编程之 Optional
  • 海底世界-第16届蓝桥第4次STEMA测评Scratch真题第5题
  • 【jax】ms(毫秒)和 μs(微秒)
  • Leetcode395.至少有 K 个重复字符的最长子串
  • Qt从零开始(1)了解
  • Golang | 倒排索引Value的设计
  • Python爬虫实战:获取ya马逊最新销售飙升榜数据并做分析,为电商选品做参考
  • 【AI】MCP协议,AI界的USB接口
  • FastAPI系列06:FastAPI响应(Response)
  • leetcode--盛最多水的容器,接雨水
  • 数值分析、数值代数之追赶法
  • Linux课程五课---Linux进程认识1
  • MySQL----查询
  • 树莓派超全系列教程文档--(43)树莓派内核简介及更新
  • 机器学习基础——Seaborn使用
  • C++11
  • 自然语言处理之机器翻译:Statistical Machine Translation(SMT)的评估方法解析与创新实践
  • 小集合 VS 大集合:MySQL 去重计数性能优化
  • 常用第三方库:sqflite数据库应用
  • Python语言基础知识详解:数据类型及运算
  • 【MQ篇】RabbitMQ之消费失败重试!
  • 2、Linux操作系统下,ubuntu22.04版本安装搜狗输入法
  • <PLC><汇川><工控>汇川PLC实现光纤缠绕设备