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 |
高度灵活的模板组合 |
本地存储 |
持久化数据(如用户偏好) |
页面刷新后数据不丢失 |