vue.js

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > vue.js > Vue3组件通信方式

Vue3实现组件通信的14种方式详解与实战

作者:编程随想_Code

在Vue3中,组件通信仍然是一个非常重要的话题,因为在大多数应用程序中,不同的组件之间需要进行数据传递和交互,在Vue3中,组件通信有多种方式可供选择,本文给大家介绍了Vue3实现组件通信的14种方式,需要的朋友可以参考下

一、父子组件通信

1. props 父传子

适用场景:父组件向子组件传递数据
核心用法defineProps 接收 props

<!-- 父组件 Parent.vue -->
<template>
  <Child :message="parentMsg" />
</template>
<script setup>
import { ref } from 'vue';
import Child from './Child.vue';

const parentMsg = ref('Hello from Parent');
</script>

<!-- 子组件 Child.vue -->
<template>
  <div>父组件传递的props: {{ message }}</div>
</template>
<script setup>
const props = defineProps({
  message: String
});
</script>

注意事项

2. defineEmits 子传父

适用场景:子组件向父组件传递数据
核心用法defineEmits 定义自定义事件

<!-- 子组件 Child.vue -->
<template>
  <button @click="sendData">发送数据</button>
</template>
<script setup>
const emit = defineEmits(['update']);
function sendData() {
  emit('update', 'Data from Child');
}
</script>

<!-- 父组件 Parent.vue -->
<template>
  <Child @update="handleUpdate" />
</template>
<script setup>
function handleUpdate(data) {
  console.log('接收到子组件数据:', data);
}
</script>

补充

3. $attrs 属性透传

适用场景:透传未声明的属性到子组件
核心用法$attrs 自动继承父组件未声明的属性

<!-- 父组件 Parent.vue -->
<template>
  <Child :customAttr="123" />
</template>

<!-- 子组件 Child.vue -->
<template>
  <div v-attrs="$attrs"></div>
</template>
<script setup>
import { useAttrs } from 'vue';
const attrs = useAttrs();
console.log(attrs.customAttr); // 输出 123
</script>

4. ref + defineExpose

适用场景:父组件调用子组件方法或访问子组件数据
核心用法ref 获取子组件实例,defineExpose 暴露方法/数据

<!-- 父组件 Parent.vue -->
<template>
  <Child ref="childRef" />
  <button @click="callChildMethod">调用子组件方法</button>
</template>
<script setup>
import { ref } from 'vue';
import Child from './Child.vue';

const childRef = ref(null);
function callChildMethod() {
  childRef.value?.childMethod();
}
</script>

<!-- 子组件 Child.vue -->
<script setup>
function childMethod() {
  console.log('子组件方法被调用');
}
defineExpose({ childMethod });
</script>

注意事项

5. v-model 双向绑定

适用场景:实现父子组件双向数据绑定
核心用法modelValue + update:modelValue

<!-- 父组件 Parent.vue -->
<template>
  <Child v-model="value" />
</template>
<script setup>
import { ref } from 'vue';
const value = ref('初始值');
</script>

<!-- 子组件 Child.vue -->
<template>
  <input :value="modelValue" @input="updateValue" />
</template>
<script setup>
const props = defineProps(['modelValue']);
const emit = defineEmits(['update:modelValue']);
function updateValue(e) {
  emit('update:modelValue', e.target.value);
}
</script>

二、兄弟组件通信

6. 父组件中转

适用场景:兄弟组件通过父组件共享数据

<!-- 父组件 Parent.vue -->
<template>
  <BrotherA @data-change="handleDataChange" />
  <BrotherB :shared-data="sharedData" />
</template>
<script setup>
import { ref } from 'vue';
const sharedData = ref('');
function handleDataChange(data) {
  sharedData.value = data;
}
</script>

7. mitt 事件总线

适用场景:轻量级解耦通信(无共同父组件)
核心用法mitt 创建事件中心

// eventBus.js
import mitt from 'mitt';
export const emitter = mitt();

// 组件A
<script setup>
import { emitter } from './eventBus.js';
function sendData() {
  emitter.emit('brother-event', { id: 1 });
}
</script>

// 组件B
<script setup>
import { emitter } from './eventBus.js';
emitter.on('brother-event', (data) => {
  console.log('接收到数据:', data);
});
</script>

8. 全局状态管理(Pinia/Vuex)

适用场景:复杂应用中的全局状态共享

// store/counter.js (Pinia)
import { defineStore } from 'pinia';
export const useCounterStore = defineStore('counter', {
  state: () => ({ count: 0 }),
  actions: { increment() { this.count++; } }
});

// 组件A
<script setup>
import { useCounterStore } from '@/store/counter';
const store = useCounterStore();
store.increment();
</script>

// 组件B
<script setup>
import { useCounterStore } from '@/store/counter';
const store = useCounterStore();
console.log(store.count);
</script>

三、跨层级通信

9. provide/inject

适用场景:祖孙组件或深层嵌套组件通信

<!-- 父组件 Parent.vue -->
<script setup>
import { provide, ref } from 'vue';
const theme = ref('dark');
provide('theme', theme);
</script>

<!-- 子组件 Child.vue -->
<script setup>
import { inject } from 'vue';
const theme = inject('theme');
console.log('当前主题:', theme.value);
</script>

10. 全局状态管理(Pinia/Vuex)

与兄弟组件通信中的 Pinia 用法一致,适用于跨层级状态共享。

四、其他通信方式

11. 浏览器本地存储(localStorage/sessionStorage)

适用场景:持久化数据共享(如用户偏好设置)

// 存储数据
localStorage.setItem('user', JSON.stringify({ name: '豆豆' }));

// 读取数据
const user = JSON.parse(localStorage.getItem('user'));
console.log(user.name); // 输出 豆豆

12. 全局 window 对象

适用场景:临时跨组件通信(慎用)

12. 全局 window 对象
适用场景:临时跨组件通信(慎用)

13. ES6 模块化(import/export)

适用场景:常量或工具函数共享

// constants.js
export const API_URL = 'https://api.example.com';

// 组件中使用
import { API_URL } from '@/constants';
console.log(API_URL); // 输出 https://api.example.com

14. 作用域插槽(Slot Props)

适用场景:父组件向子组件传递函数或配置对象

<!-- 父组件 Parent.vue -->
<template>
  <Child>
    <template #default="{ config }">
      <div :style="config">{{ config.title }}</div>
    </template>
  </Child>
</template>

<!-- 子组件 Child.vue -->
<script setup>
import { reactive } from 'vue';
const config = reactive({ title: 'Slot Injected Config' });
</script>

五、最佳实践建议

优先选择标准化方案

80% 场景使用 props + emits

复杂场景选择 provide/inject 或状态管理库。

避免过度使用全局状态

仅当数据需要在多组件间共享时使用 Pinia/Vuex。

善用 $attrs

减少子组件 props 定义,实现属性透传。

谨慎操作 ref

仅在必要时直接调用子组件方法,保持组件解耦。

事件命名规范

使用 on[EventName] 格式,如 on:update

六、总结

Vue3 提供了丰富且灵活的组件通信方式,开发者应根据具体场景选择最优方案。以下是常见场景的推荐选择:

场景推荐通信方式
父子通信props + defineEmits
兄弟组件通信mitt 或父组件中转
跨层级通信provide/inject 或 Pinia
全局状态共享Pinia 或 Vuex
临时数据共享localStorage 或 window

掌握这些通信方式后,可以更高效地构建复杂应用。建议将示例代码复制到项目中运行,观察不同方式的数据流向和效果差异。

以上就是Vue3实现组件通信的14种方式详解与实战的详细内容,更多关于Vue3组件通信方式的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文