Vue3组件通信方法清单
1. Props / Emits(父子通信)
适用场景
父组件传递数据给子组件,子组件通知父组件。
代码示例
<!-- 父组件 -->
<template><ChildComponent :message="parentMsg" @update="handleUpdate"/>
</template><script setup>
import { ref } from 'vue';
import ChildComponent from './Child.vue';const parentMsg = ref('Hello from Parent');
const handleUpdate = (newMsg) => {parentMsg.value = newMsg;
};
</script><!-- 子组件 Child.vue -->
<template><button @click="$emit('update', 'New message')">点击更新: {{ message }}</button>
</template><script setup>
defineProps(['message']);
defineEmits(['update']);
</script>
2. v-model(双向绑定)
适用场景
简化父子组件的双向数据绑定。
代码示例
<!-- 父组件 -->
<template><CustomInput v-model="inputValue" />
</template><script setup>
import { ref } from 'vue';
const inputValue = ref('');
</script><!-- 子组件 CustomInput.vue -->
<template><input:value="modelValue"@input="$emit('update:modelValue', $event.target.value)"/>
</template><script setup>
defineProps(['modelValue']);
defineEmits(['update:modelValue']);
</script>
3. provide / inject(跨层级通信)
适用场景
祖先组件向后代组件传递数据,避免逐层传递 props。
代码示例
<!-- 祖先组件 -->
<template><MiddleComponent />
</template><script setup>
import { provide, ref } from 'vue';
const theme = ref('dark');
provide('theme', theme); // 提供数据
</script><!-- 后代组件(任意层级) -->
<script setup>
import { inject } from 'vue';
const theme = inject('theme'); // 注入数据
</script>
4. 事件总线(任意组件通信)
适用场景
非父子组件间的通信,如兄弟组件或跨多层级组件。
代码示例(使用 mitt)
// 创建事件总线(utils/eventBus.js)
import mitt from 'mitt';
export const emitter = mitt();// 组件A(发送事件)
import { emitter } from './eventBus';
emitter.emit('message', 'Hello from A');// 组件B(接收事件)
import { emitter } from './eventBus';
emitter.on('message', (msg) => {console.log(msg); // "Hello from A"
});
5. ref / 模板引用
适用场景
父组件直接调用子组件的方法或访问其数据。
代码示例
<!-- 父组件 -->
<template><ChildComponent ref="childRef" /><button @click="callChildMethod">调用子组件方法</button>
</template><script setup>
import { ref } from 'vue';
const childRef = ref(null);const callChildMethod = () => {childRef.value.sayHello(); // 直接调用子组件方法
};
</script><!-- 子组件 -->
<script setup>
const sayHello = () => {console.log('Hello from Child!');
};
// 暴露方法给父组件
defineExpose({ sayHello });
</script>
6. Pinia(全局状态管理)
适用场景
多个组件共享复杂状态(如用户登录信息)。
代码示例
// 定义 store
import { defineStore } from 'pinia';
export const useUserStore = defineStore('user', {state: () => ({ name: 'Alice' }),actions: {updateName(newName) {this.name = newName;}}
});// 组件中使用
import { useUserStore } from '@/store/user';
const userStore = useUserStore();
console.log(userStore.name); // "Alice"
userStore.updateName('Bob'); // 调用 action
7. 插槽(Slot)通信
适用场景
父组件向子组件传递模板片段。
代码示例
<!-- 子组件 -->
<template><div class="card"><slot name="header" :user="user"></slot><slot></slot></div>
</template><script setup>
const user = { name: 'Alice' };
</script><!-- 父组件 -->
<template><ChildComponent><template #header="{ user }"><h1>{{ user.name }}的头像</h1></template><p>这是默认插槽内容</p></ChildComponent>
</template>
8. Local Storage / Cookies
适用场景
持久化存储数据,跨页面共享。
注意,只有同源的页面才能共享localstorage的数据
代码示例
// 存储数据
localStorage.setItem('theme', 'dark');// 读取数据(任何组件中均可)
const theme = localStorage.getItem('theme');
总结:如何选择?
方法 | 适用场景 | 优点 |
---|---|---|
Props/Emits | 父子组件简单通信 | 直观、Vue 官方推荐 |
v-model | 表单双向绑定 | 语法糖简化代码 |
provide/inject | 跨层级组件通信 | 避免 prop 逐层传递 |
事件总线 | 任意组件间通信 | 解耦、灵活 |
ref | 父组件调用子组件方法 | 直接访问子组件实例 |
Pinia | 复杂全局状态管理 | 类型安全、DevTools 支持 |
插槽 | 父组件定制子组件 UI | 高度灵活的模板组合 |
本地存储 | 持久化数据(如用户偏好) | 页面刷新后数据不丢失 |