当前位置: 首页 > news >正文

除了provide和inject,Vue3还有哪些用于组件通信的方式?

目录

一、父子组件通信(最基础场景)

1. props + emit(核心方案)

2. v-model(双向绑定语法糖)

3. ref + 组件实例(父访问子方法 / 数据)

4. $parent / $children(层级访问,不推荐)

二、兄弟组件 / 跨层级组件通信

1. 事件总线(Event Bus)

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

三、通过插槽(Slots)传递内容 / 数据

四、attrs 与 listeners(属性透传)

总结:不同场景的选择建议


在 Vue3 中,组件通信的方式根据组件关系(父子、兄弟、跨层级、全局)有所不同,除了provide/inject,还有以下常用方式:

一、父子组件通信(最基础场景)

1. props + emit(核心方案)
  • 作用props 实现父组件向子组件传递数据;emit 实现子组件向父组件传递事件 / 数据。
  • 用法示例
<!-- 父组件 Parent.vue -->
<template><!-- 父传子:通过props传递message --><Child :message="parentMsg" @handleChange="onChildChange" />
</template>
<script setup>
import { ref } from 'vue'
import Child from './Child.vue'
const parentMsg = ref('来自父组件的数据')
const onChildChange = (newVal) => {parentMsg.value = newVal // 接收子组件传递的数据
}
</script><!-- 子组件 Child.vue -->
<template><div><p>{{ message }}</p><button @click="sendToParent">向父组件传值</button></div>
</template>
<script setup>
import { defineProps, defineEmits } from 'vue'
// 定义接收的props
const props = defineProps({message: {type: String,default: ''}
})
// 定义触发的事件
const emit = defineEmits(['handleChange'])
const sendToParent = () => {emit('handleChange', '来自子组件的新数据') // 子传父:通过emit触发事件
}
</script>
  • 适用场景:直接父子组件,数据传递简单、单向(父→子)或事件触发(子→父)。
2. v-model(双向绑定语法糖)
  • 作用:简化 “父组件 props 传递 + 子组件 emit 回传” 的双向绑定逻辑,本质是 props + emit 的语法糖。
  • 原理:父组件用 v-model:xxx="value" 时,等价于:
    • 向子组件传递 xxx props
    • 监听子组件触发的 update:xxx 事件
  • 用法示例
<!-- 父组件 -->
<template><Child v-model:count="num" /> <!-- 双向绑定count -->
</template>
<script setup>
import { ref } from 'vue'
import Child from './Child.vue'
const num = ref(0)
</script><!-- 子组件 -->
<template><button @click="add">count: {{ count }}</button>
</template>
<script setup>
import { defineProps, defineEmits } from 'vue'
const props = defineProps({ count: Number })
const emit = defineEmits(['update:count']) // 固定事件名:update:xxx
const add = () => {emit('update:count', props.count + 1) // 触发更新,父组件num会同步变化
}
</script>
  • 适用场景:需要父子组件双向同步数据(如表单组件、计数器等)。
3. ref + 组件实例(父访问子方法 / 数据)
  • 作用:父组件通过 ref 获取子组件实例,直接访问子组件的方法、数据或 DOM。
  • 用法示例
<!-- 父组件 -->
<template><Child ref="childRef" /><button @click="callChildMethod">调用子组件方法</button>
</template>
<script setup>
import { ref } from 'vue'
import Child from './Child.vue'
const childRef = ref(null) // 绑定子组件实例
const callChildMethod = () => {childRef.value?.childMethod() // 调用子组件的方法console.log(childRef.value.childData) // 访问子组件的数据
}
</script><!-- 子组件 -->
<script setup>
import { ref } from 'vue'
const childData = ref('子组件的数据')
const childMethod = () => {console.log('子组件方法被调用')
}
// 需通过defineExpose暴露(否则父组件无法访问)
defineExpose({ childData, childMethod })
</script>
  • 注意:子组件需用 defineExpose 显式暴露需要被访问的属性 / 方法(默认封闭)。
  • 适用场景:父组件需要主动触发子组件的逻辑(如表单重置、弹窗显示等)。
4. $parent / $children(层级访问,不推荐)
  • 作用:子组件通过 $parent 访问父组件实例;父组件通过 $children 访问子组件列表。
  • 缺点:强依赖组件层级,若组件嵌套关系变化(如增加中间层),会导致逻辑失效,维护性差。
  • 用法(仅作了解,不推荐使用):
<!-- 子组件中访问父组件 -->
<script setup>
import { getCurrentInstance } from 'vue'
const instance = getCurrentInstance()
console.log(instance.parent) // 父组件实例
</script>

二、兄弟组件 / 跨层级组件通信

1. 事件总线(Event Bus)
  • 作用:通过一个全局事件中心,实现任意组件间的通信(发布 - 订阅模式)。
  • 实现方式:Vue3 移除了内置的 $on / $off,需用第三方库(如 mitt)或自定义事件中心。
  • 用法示例(基于 mitt):
    1. 安装:npm install mitt
    2. 创建事件总线:
      // bus.js
      import mitt from 'mitt'
      export const bus = mitt()
      
    3. 组件 A(发布事件):
      <script setup>
      import { bus } from './bus.js'
      const sendMsg = () => {bus.emit('msgEvent', '来自组件A的消息') // 发布事件
      }
      </script>
      
    4. 组件 B(订阅事件):
      <script setup>
      import { bus } from './bus.js'
      import { onMounted, onUnmounted } from 'vue'
      onMounted(() => {bus.on('msgEvent', (data) => { // 订阅事件console.log('收到消息:', data)})
      })
      onUnmounted(() => {bus.off('msgEvent') // 解绑事件,避免内存泄漏
      })
      </script>
      
  • 适用场景:中小型项目,非全局的跨组件通信(如兄弟组件、隔代组件)。
2. 状态管理库(Pinia / Vuex)
  • 作用:通过全局状态池管理数据,任意组件可共享、修改数据(解决 “全局状态共享” 问题)。
  • Vue3 推荐用 Pinia(Vuex 的替代者,更简洁):
    1. 定义 store:
      // stores/counter.js
      import { defineStore } from 'pinia'
      export const useCounterStore = defineStore('counter', {state: () => ({ count: 0 }),actions: {increment() { this.count++ }}
      })
      
    2. 任意组件使用:
      <script setup>
      import { useCounterStore } from './stores/counter.js'
      const store = useCounterStore()
      console.log(store.count) // 访问全局状态
      store.increment() // 修改全局状态(所有组件会同步更新)
      </script>
      
  • 适用场景:大型项目,需要全局共享状态(如用户信息、主题配置、购物车数据等)。

三、通过插槽(Slots)传递内容 / 数据

  • 作用:父组件向子组件传递 “模板内容”,作用域插槽还可实现子组件向父组件传递数据。
  • 分类
    • 默认插槽:传递基础内容;
    • 具名插槽:传递多个不同区域的内容;
    • 作用域插槽:子组件向父组件传递数据,父组件根据数据渲染内容。
  • 作用域插槽示例(子传父数据):
    <!-- 子组件 Child.vue -->
    <template><!-- 子组件通过v-slot传递数据(user) --><slot name="userInfo" :user="userData"></slot>
    </template>
    <script setup>
    import { ref } from 'vue'
    const userData = ref({ name: '张三', age: 20 }) // 子组件的数据
    </script><!-- 父组件 Parent.vue -->
    <template><Child><!-- 父组件接收子组件传递的user数据并渲染 --><template #userInfo="{ user }"><p>姓名:{{ user.name }}</p><p>年龄:{{ user.age }}</p></template></Child>
    </template>
    
  • 适用场景:父组件需要控制子组件的部分 UI 渲染,且渲染内容依赖子组件的数据。

四、attrs 与 listeners(属性透传)

  • 作用:当组件嵌套多层时,父组件的属性 / 事件可通过 attrs 透传给深层子组件(避免每层手动传递)。
  • Vue3 中$attrs 包含所有未被 props 接收的属性(包括事件),可通过 v-bind="$attrs" 透传。
  • 用法示例
    <!-- 父组件 -->
    <template><MiddleComponent msg="透传的消息" @notify="handleNotify" />
    </template><!-- 中间组件 MiddleComponent.vue(无需处理,直接透传) -->
    <template><DeepComponent v-bind="$attrs" /> <!-- 将attrs透传给深层组件 -->
    </template><!-- 深层组件 DeepComponent.vue -->
    <template><p>{{ msg }}</p> <!-- 直接使用透传的msg -->
    </template>
    <script setup>
    import { defineProps, defineEmits } from 'vue'
    const props = defineProps({ msg: String })
    const emit = defineEmits(['notify']) // 可触发透传的事件
    </script>
    
  • 适用场景:组件库开发、多层嵌套组件的属性 / 事件透传(如 UI 组件的原生属性透传)。

总结:不同场景的选择建议

组件关系推荐方式特点
父子组件props + emit / v-model简单直接,单向 / 双向绑定
父子组件(交互)ref + 组件实例父主动调用子组件逻辑
兄弟 / 隔代组件事件总线(mitt)/ provide/inject轻量跨层级通信
全局任意组件Pinia(状态管理)全局状态共享,适合大型项目
传递模板内容插槽(尤其是作用域插槽)灵活控制子组件 UI 渲染
多层属性透传attrs 透传简化嵌套组件的属性传递

根据项目规模和组件关系选择合适的方式,可大幅提升代码的可维护性。

http://www.dtcms.com/a/523503.html

相关文章:

  • React 表单与事件
  • AI代码开发宝库系列:FAISS向量数据库
  • 前端埋点学习
  • Spring AI与DeepSeek实战:打造企业级知识库+系统API调用
  • 秦皇岛市建设局网站关于装配式专家做运动特卖的网站
  • j2ee 建设简单网站设计婚纱网站
  • C++类和对象(中):const 成员函数与取地址运算符重载
  • 数据结构 散列表—— 冲突解决方法
  • 箭头函数和普通函数有什么区别
  • Spring Boot 缓存知识体系大纲
  • 破局政务数字化核心难题:金仓数据库以国产化方案引领电子证照系统升级之路
  • XML:从基础到 Schema 约束的全方位解析
  • 技术引领场景革新|合合信息PRCV论坛聚焦多模态文本智能前沿实践
  • 海南网站建设网络货运平台有哪些
  • 系统架构设计师备考第53天——业务逻辑层设计
  • 科技创新与数字化制造转型在“十五五”规划中的意义
  • 网站开发最新技术wordpress4.7.4密码
  • HarmonyOS方舟编译器与运行时优化
  • HarmonyOS AI能力集成与端侧推理实战
  • 自己做公众号和小说网站推广济南网站建设艮安
  • 阿里云国际站GPU:阿里云GPU的应用场景有哪些?
  • 【工具】Scrcpy|安卓投屏电脑的开源工具Scrcpy的安装及看电视注意事项
  • penCV轻松入门_面向python(第七章 图像平滑处理)
  • html5移动网站开发流程各类设计型网站
  • 使用C#代码在Excel中创建数据透视表
  • 反爬克星还是效率神器?Browser-Use+cpolar重构Web自动化逻辑
  • 《KingbaseES数据库:首个多院区异构多活容灾架构,浙人医创新开新篇》
  • MySQL 的 MyISAM 与 InnoDB 存储引擎的核心区别
  • 【Qt开发】容器类控件(一)-> QGroupBox
  • 生活电器:重构家居体验的产业变革与发展探索