Vue3 入门教程
组件通信汇总
本教程共 40 篇 · 第 27 篇 · 更新于 2026-07-29 · 约 7 分钟阅读
VueVue3 入门教程组件通信PropsEventsv-modelProvide Inject
27. 组件通信汇总
本节目标:系统梳理 Vue 组件通信的所有方式,学会在不同场景下选择最合适的方案。
组件通信方式总览
| 方式 | 方向 | 跨层级 | 适用场景 |
|---|---|---|---|
| Props | 父 → 子 | 否 | 父传数据给子 |
| Events | 子 → 父 | 否 | 子传消息给父 |
| v-model | 双向 | 否 | 表单类组件双向绑定 |
| Provide / Inject | 祖先 → 后代 | 是 | 跨层级传数据 |
| $attrs | 父 → 子 | 否 | 透传未声明属性 |
| Pinia / Vuex | 任意 | 任意 | 全局状态管理 |
Props——父传子
最基础的通信方式。父组件通过属性传值,子组件用 defineProps() 接收:
<!-- 父组件 -->
<BlogPost :title="post.title" :author="post.author" />
<!-- 子组件 -->
<script setup>
const props = defineProps(['title', 'author'])
</script>
特点:单向数据流,prop 只读,类型可验证。
适用:绝大多数父子数据传递场景。
Events——子传父
子组件 emit 事件,父组件监听事件:
<!-- 子组件 -->
<button @click="$emit('delete', id)">删除</button>
<!-- 父组件 -->
<MyItem @delete="handleDelete" />
特点:事件不冒泡,只能监听直接子组件。
适用:子组件通知父组件做某事(删除、提交、切换等)。
v-model——父子双向绑定
语法糖,本质是 Props + Events 的组合:
<!-- 父组件 -->
<SearchInput v-model="keyword" />
<!-- 子组件 -->
<script setup>
const model = defineModel()
</script>
特点:自动同步,支持多个绑定和自定义修饰符。
适用:自定义表单组件,父子需要保持数据同步。
Provide / Inject——祖先到后代
跳过中间层级,直接跨级传递:
// 祖先
provide('theme', 'dark')
// 后代
const theme = inject('theme', 'light') // 默认值 'light'
特点:适合深层嵌套,提供方可把修改方法一起 provide。
适用:主题、用户信息、语言等全局但局部的共享数据。
NoteProvide / Inject 不是状态管理工具。它适合”某个组件树内部共享”,不适合整个应用的状态。
$attrs——透传属性
未声明为 prop 的属性自动传给子组件根元素:
<MyButton class="large" @click="handler" />
class 和 @click 没被声明为 prop,就会透传。用 inheritAttrs: false 关闭自动继承后,可以手动控制:
<button v-bind="$attrs">Click</button>
特点:适合做”透明包装组件”,把属性透传给内部元素。
适用:封装第三方组件、高阶组件。
怎么选择
按场景一步步判断:
- 父传子数据 → Props
- 子传父消息 → Events
- 表单双向同步 → v-model
- 跨多层传数据 → Provide / Inject
- 透传属性给内部元素 → $attrs
- 全局应用状态 → Pinia / Vuex
一个综合例子
假设一个 UserCard 组件,展示用户名和头像,点击可以展开详情:
<!-- 祖先:App.vue -->
<script setup>
import { provide } from 'vue'
provide('theme', 'dark')
</script>
<!-- 中间层:UserList.vue -->
<!-- 不用管 theme,也不需要传 -->
<!-- 后代:UserCard.vue -->
<script setup>
import { inject } from 'vue'
// 跨级注入主题
const theme = inject('theme')
// Props 接收数据
const props = defineProps({
name: String,
avatar: String
})
// Events 通知父组件
const emit = defineEmits(['expand'])
// v-model 双向绑定
const model = defineModel()
</script>
一个组件里经常多种通信方式同时使用——这不是”选一个”,而是”各管各的”。
常见误区
| 误区 | 正确做法 |
|---|---|
| 所有数据都用 props 层层传递 | 跨层用 Provide / Inject |
| 跨层级也用 Events 冒泡 | 事件不冒泡,用 provide 函数或状态管理 |
| Provide / Inject 替代 Pinia | 它们定位不同,不是替代关系 |
| 每个组件都全局注册 | 大多数组件局部注册 |
本节回顾
- Props 父传子,Events 子传父,两者组合是最常用的
- v-model 是 Props + Events 的语法糖,适合表单组件
- Provide / Inject 解决跨层级传递
- $attrs 做属性透传
- 全局状态用专门的库(Pinia)
- 一个组件可以同时使用多种通信方式