基于本文回答
0
评论

Vue 组件间通信有哪些方式?

知识点图片

Vue 组件间的通信方式非常丰富,适用于不同的场景(父子、兄弟、跨级、全局)。为了方便记忆和理解,我们可以将其按组件关系适用场景进行分类。

以下是 Vue 中主流的通信方式总结:


1. 父子组件通信

这是最基础、最常用的通信方式。

A. Props (父传子)

  • 描述:父组件通过属性绑定的方式将数据传递给子组件,子组件通过 props 接收。
  • 适用:单向数据流,父组件向子组件传递数据。
  • 代码简述
    html
    <!-- 父组件 -->
    <Child :msg="message" />
    
    <!-- 子组件 -->
    <script setup>
    defineProps(['msg'])
    </script>

B. $emit (子传父)

  • 描述:子组件通过触发自定义事件,将数据作为参数传递给父组件。
  • 适用:子组件通知父组件改变数据或执行操作。
  • 代码简述
    js
    // 子组件
    const emit = defineEmits(['update'])
    emit('update', data)
    
    // 父组件
    <Child @update="handleUpdate" />

C. v-model (双向绑定)

  • 描述:本质是 props + emit 的语法糖。
  • Vue 2:使用 value prop 和 input 事件(或 .sync 修饰符)。
  • Vue 3:默认使用 modelValue prop 和 update:modelValue 事件。支持多个 v-model。
  • 适用:表单组件或需要双向同步数据的组件。

D. $refs / defineExpose (父访子)

  • 描述:父组件通过 ref 获取子组件实例,直接调用子组件的方法或访问数据。
  • 注意:在 Vue 3 <script setup> 中,子组件默认是关闭的,必须通过 defineExpose 暴露属性或方法,父组件才能访问。
  • 适用:父组件需要主动触发子组件的某个功能(如:打开弹窗、重置表单)。

2. 跨级组件通信 (祖先与后代)

当组件嵌套层级较深,中间组件不需要数据时,使用 Props 逐层传递(Props Drilling)会很麻烦。

A. Provide / Inject (依赖注入)

  • 描述:祖先组件使用 provide 提供数据,任意深度的后代组件使用 inject 接收数据。
  • 特点:默认不是响应式的,如果需要响应式,传递的数据必须是 refreactive 对象。
  • 适用:深层嵌套组件、编写插件或组件库。

B. $attrs (透传 Attributes)

  • 描述:包含了父作用域中不作为 propsemits 被识别的 attribute 绑定(class, style, id 等)。
  • Vue 3 变化:Vue 2 中的 $listeners 已被合并到 $attrs 中。
  • 适用:封装高阶组件,或者将属性“透传”给内部的根元素。

3. 兄弟组件或任意组件通信

A. Event Bus (事件总线)

  • 描述:创建一个全局空的 Vue 实例作为事件中心,通过 $on 监听,$emit 触发,$off 销毁。
  • Vue 3 现状Vue 3 移除了 $on, $off, $once 实例方法,官方不再支持自带的 Event Bus。
  • 替代方案:在 Vue 3 中推荐使用第三方库,如 mitttiny-emitter
  • 适用:轻量级的跨组件通信,项目规模较小。

B. Vuex / Pinia (状态管理)

  • 描述:集中式存储管理应用的所有组件的状态。
  • 现状Pinia 是 Vue 3 官方推荐的状态管理库(Vuex 5 的精神继任者),比 Vuex 更轻量、API 更友好(去掉了 mutation,支持 Composition API)。
  • 适用:中大型项目,多个组件共享状态,逻辑复杂。

4. 其他方式 (较少用或特定场景)

  • $parent / $root
    • 子组件可以直接访问父组件实例或根实例。
    • 缺点:耦合度太高,难以维护,通常不推荐使用。
  • 浏览器本地存储 (localStorage / sessionStorage)
    • 数据持久化,不同页面或组件间共享数据,但不是响应式的(需要配合监听 storage 事件或自定义 hook)。
  • Window 全局变量
    • 最原始的方式,极不推荐,容易造成命名冲突和难以追踪的数据流。

总结:如何选择?

场景 推荐方式 备注
\to Props 最标准方式
\to $emit 最标准方式
\leftrightarrow v-model 双向绑定首选
父调用子方法 ref + defineExpose 比如控制弹窗显示
祖先 \to 后代 Provide / Inject 避免 Props 层层传递
兄弟/全局 (简单) Event Bus (mitt) 小项目
兄弟/全局 (复杂) Pinia (或 Vuex) 大项目首选
组件库封装 $attrs 透传属性
右滑查看面试常问