是的,Vue3 组件通信是构建复杂应用的核心概念,掌握多种方式能提升开发效率。以下是 Vue3 中常见的 6 种组件通信方式,我会基于官方文档和最佳实践,逐步解释每种方式的原理、适用场景和简单示例(使用中文)。这些方式各有优缺点,建议根据具体需求选择。

1. Props(属性传递)

原理:父组件通过属性向子组件传递数据,子组件通过 defineProps 接收。这是单向数据流的推荐方式,适合父子组件通信。
适用场景:父组件控制子组件的状态或配置。
示例代码

<!-- 父组件 -->
<template>
  <ChildComponent :message="parentMessage" />
</template>
<script setup>
import { ref } from 'vue';
import ChildComponent from './ChildComponent.vue';
const parentMessage = ref('Hello from Parent');
</script>

<!-- 子组件 -->
<template>
  <div>{{ message }}</div>
</template>
<script setup>
defineProps(['message']);
</script>

2. Emits(事件触发)

原理:子组件通过 defineEmits 定义事件,并用 $emit 触发事件,父组件监听并处理。实现子向父的通信。
适用场景:子组件需要通知父组件状态变化(如按钮点击)。
示例代码

<!-- 子组件 -->
<template>
  <button @click="notifyParent">通知父组件</button>
</template>
<script setup>
const emit = defineEmits(['custom-event']);
function notifyParent() {
  emit('custom-event', 'Data from Child');
}
</script>

<!-- 父组件 -->
<template>
  <ChildComponent @custom-event="handleEvent" />
</template>
<script setup>
function handleEvent(data) {
  console.log(data); // 输出: Data from Child
}
</script>

3. Provide/Inject(提供/注入)

原理:祖先组件用 provide 提供数据,子孙组件用 inject 注入使用。适合跨层级组件通信,避免层层传递 props。
适用场景:主题切换、全局配置等深度嵌套组件。
示例代码

<!-- 祖先组件 -->
<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');
console.log(theme.value); // 输出: dark
</script>

4. Vuex/Pinia(状态管理库)

原理:使用状态管理库(如 Vuex 或 Pinia)创建全局 store,组件通过 useStore 访问共享状态。Pinia 是 Vue3 推荐的新方案,更轻量。
适用场景:大型应用中多个组件共享状态(如用户登录信息)。
示例代码(以 Pinia 为例):

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

// 组件中使用
<script setup>
import { useCounterStore } from './store';
const counter = useCounterStore();
</script>
<template>
  <button @click="counter.increment">增加: {{ counter.count }}</button>
</template>

5. Slots(插槽)

原理:父组件通过插槽向子组件传递内容或作用域数据。Vue3 支持作用域插槽(scoped slots),允许子组件暴露数据给父组件。
适用场景:可复用 UI 组件(如列表、卡片),父组件自定义内容。
示例代码

<!-- 子组件 -->
<template>
  <div>
    <slot name="header" :user="user"></slot>
  </div>
</template>
<script setup>
import { ref } from 'vue';
const user = ref({ name: 'Alice' });
</script>

<!-- 父组件 -->
<template>
  <ChildComponent>
    <template #header="{ user }">
      <h1>{{ user.name }}</h1> <!-- 输出: Alice -->
    </template>
  </ChildComponent>
</template>

6. Template Refs(模板引用)

原理:使用 ref 属性直接访问子组件实例或 DOM 元素,通过 defineExpose 暴露子组件方法。适合需要直接操作子组件的场景。
适用场景:焦点管理、动画控制或调用子组件方法。
示例代码

<!-- 子组件 -->
<script setup>
import { ref } from 'vue';
const childMethod = () => {
  console.log('Child method called');
};
defineExpose({ childMethod });
</script>

<!-- 父组件 -->
<template>
  <ChildComponent ref="childRef" />
  <button @click="callChildMethod">调用子方法</button>
</template>
<script setup>
import { ref } from 'vue';
import ChildComponent from './ChildComponent.vue';
const childRef = ref(null);
function callChildMethod() {
  childRef.value.childMethod(); // 输出: Child method called
}
</script>

总结

  • 核心原则:Vue3 强调单向数据流和组件解耦,优先使用 Props/Emits 和 Composition API(如 refreactive)。
  • 选择建议:简单父子通信用 Props/Emits;跨层级用 Provide/Inject;全局状态用 Pinia;动态内容用 Slots;特殊交互用 Refs。
  • 实际使用:这些方式在项目中很常见,我(作为AI)基于知识库提供解释,但实际开发中需结合场景优化。如果您有具体问题(如性能考量或代码优化),欢迎进一步讨论! 😊
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐