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

组件通信与注册

文章目录

  • 前言
  • 一、通信方式总览
    • 1.1 选型指南
  • 二、Props / Emit(父子通信)
    • 2.1 单向数据流
    • 2.2 v-model 本质
    • 2.3 常见场景
  • 三、provide / inject(跨层级通信)
    • 3.1 基本用法
    • 3.2 响应式 provide
    • 3.3 应用场景
    • 3.4 易混淆点
  • 四、事件总线 mitt
    • 4.1 Vue 3 的变化
    • 4.2 封装与使用
    • 4.3 适用场景
  • 五、Pinia / Vuex(全局状态)
    • 5.1 何时使用
    • 5.2 Pinia 基本用法
    • 5.3 与其他方式对比
  • 六、组件注册方式
    • 6.1 全局注册
    • 6.2 局部注册
    • 6.3 异步组件注册
    • 6.4 全局 vs 局部
  • 七、通信方式对比总结
  • 八、面试聚焦
    • 8.1 Props 单向数据流
    • 8.2 provide/inject 响应式
    • 8.3 全局注册无法 Tree-shaking
    • 8.4 Vue 3 事件总线
  • 九、易混淆点
  • 十、思考与练习
  • 总结

前言

组件化开发的核心问题之一,就是组件之间如何传递数据和触发行为。Vue 提供了多种通信方式,本篇会讲清楚:

  • Props / Emit(父子通信)
  • provide / inject(跨层级通信)
  • 事件总线 mitt
  • Pinia / Vuex(全局状态)
  • 组件注册方式(全局 / 局部 / 异步)

一、通信方式总览

1.1 选型指南

方式适用场景关系
Props / Emit父子数据传递、子通知父直接父子
provide / inject主题、语言包、表单上下文祖孙跨层级
mitt(事件总线)兄弟组件、无关联组件任意组件
Pinia / Vuex用户状态、权限、购物车全局共享
// 选型原则:// 1. 能用 Props/Emit 解决的,优先用 Props/Emit(数据流清晰)// 2. 跨多层级透传 → provide/inject// 3. 无关联组件 → mitt 或 Pinia// 4. 多处共享的全局状态 → Pinia

二、Props / Emit(父子通信)

2.1 单向数据流

<!-- 父组件 Parent.vue --> <script setup> import { ref } from 'vue' import Child from './Child.vue' const count = ref(0) const handleChange = (val) => { count.value = val // 父组件修改数据 } </script> <template> <Child :count="count" @change="handleChange" /> </template>
<!-- 子组件 Child.vue --> <script setup> const props = defineProps({ count: { type: Number, default: 0 } }) const emit = defineEmits(['change']) const increment = () => { // ❌ 不能直接修改 props // props.count++ // ✅ 通过 emit 通知父组件 emit('change', props.count + 1) } </script> <template> <button @click="increment">{{ count }}</button> </template>

2.2 v-model 本质

<!-- v-model 是 Props + Emit 的语法糖 --> <MyInput v-model="text" /> <!-- 等价于 --> <MyInput :modelValue="text" @update:modelValue="text = $event" /> <!-- 多个 v-model --> <MyForm v-model:name="name" v-model:age="age" />

2.3 常见场景

// 1. 父传配置:列表组件接收 items 和 loading<List:items="list":loading="loading"/>// 2. 子通知父:表单提交后 emit submit 事件// emit('submit', formData)// 3. 分页:子组件 emit page-change,父组件加载数据// emit('page-change', page)

三、provide / inject(跨层级通信)

3.1 基本用法

// 祖先组件import{provide,ref}from'vue'consttheme=ref('dark')provide('theme',theme)// 后代组件(任意层级)import{inject}from'vue'consttheme=inject('theme','light')// 第二个参数是默认值

3.2 响应式 provide

// ❌ 默认不是响应式:传递普通值provide('count',0)// 后代无法感知变化// ✅ 传递 ref 或 reactive 实现响应式constcount=ref(0)provide('count',count)// 后代组件constcount=inject('count')// count 变化时,后代视图自动更新

3.3 应用场景

// 1. 主题配置provide('theme',{color:'primary',size:'medium'})// 2. 国际化provide('locale',locale)// 3. 表单上下文(Form → FormItem)provide('formContext',{rules,validate})// 4. 全局 HTTP 实例app.provide('http',axios.create({baseURL:'/api'}))

3.4 易混淆点

// 1. 多个祖先 provide 同名 key → 取最近祖先的值// 2. inject 可指定默认值,找不到 provider 不会报错// 3. app.provide 应用级注入,任何组件都可 inject// 4. 过度使用会导致数据流难追踪,简单场景优先 Props

四、事件总线 mitt

4.1 Vue 3 的变化

// Vue 2:实例方法constbus=newVue()bus.$on('message',handler)bus.$emit('message',data)bus.$off('message',handler)// Vue 3:$on/$off/$once 已移除,使用 mittimportmittfrom'mitt'constbus=mitt()bus.on('message',(data)=>console.log(data))bus.emit('message',{text:'Hello'})bus.off('message',handler)

4.2 封装与使用

// utils/eventBus.jsimportmittfrom'mitt'exportconsteventBus=mitt()// 组件 A:发送import{eventBus}from'@/utils/eventBus'eventBus.emit('refresh-list')// 组件 B:接收import{onMounted,onUnmounted}from'vue'import{eventBus}from'@/utils/eventBus'consthandler=()=>fetchList()onMounted(()=>eventBus.on('refresh-list',handler))onUnmounted(()=>eventBus.off('refresh-list',handler))

4.3 适用场景

// ✅ 适合:兄弟组件、无直接关系的组件间通信// 如:Header 通知 Sidebar 刷新// ❌ 不适合:复杂全局状态(用 Pinia)// ❌ 不适合:父子通信(用 Props/Emit,更清晰)

五、Pinia / Vuex(全局状态)

5.1 何时使用

// 适合 Pinia 的场景:// 1. 用户登录态、Token、用户信息// 2. 购物车、收藏夹// 3. 应用全局配置(主题、语言、侧边栏状态)// 4. 多处页面共享的缓存数据

5.2 Pinia 基本用法

// stores/user.jsimport{defineStore}from'pinia'exportconstuseUserStore=defineStore('user',{state:()=>({name:'',token:''}),getters:{isLoggedIn:(state)=>!!state.token},actions:{login(token){this.token=token},logout(){this.token=''this.name=''}}})// 组件中使用import{useUserStore}from'@/stores/user'import{storeToRefs}from'pinia'constuserStore=useUserStore()const{name,isLoggedIn}=storeToRefs(userStore)// 保持响应性userStore.login('abc123')

5.3 与其他方式对比

方式数据范围持久化适用
Props/Emit父子局部数据
provide/inject组件树主题、上下文
mitt任意一次性通知
Pinia全局可插件持久化共享状态

六、组件注册方式

6.1 全局注册

import{createApp}from'vue'importAppfrom'./App.vue'importMyButtonfrom'./components/MyButton.vue'constapp=createApp(App)// 全局注册:任何模板中可直接使用app.component('MyButton',MyButton)app.mount('#app')
<!-- 任意组件模板中 --> <template> <MyButton>点击</MyButton> </template>

6.2 局部注册

<!-- 推荐:<script setup> 中导入即局部注册 --> <script setup> import MyButton from './MyButton.vue' import UserCard from './UserCard.vue' // 无需额外声明,导入即可在模板中使用 </script> <template> <MyButton /> <UserCard /> </template>

6.3 异步组件注册

import{defineAsyncComponent}from'vue'// 局部异步组件constHeavyModal=defineAsyncComponent(()=>import('./HeavyModal.vue'))// 全局异步注册app.component('HeavyModal',defineAsyncComponent(()=>import('./HeavyModal.vue')))// 带加载和错误状态constAsyncComp=defineAsyncComponent({loader:()=>import('./MyComponent.vue'),loadingComponent:LoadingSpinner,errorComponent:ErrorDisplay,delay:200,timeout:30000})

6.4 全局 vs 局部

对比项全局注册局部注册
使用范围任意组件当前组件
Tree-shaking不支持,未使用也会打包支持
依赖关系不明确清晰
适用基础通用组件(Button、Icon)业务页面组件
// 全局注册必须在 app.mount() 之前完成// <script setup> 导入的 .vue 文件自动局部注册// 组件名推荐 PascalCase,模板中可用 kebab-case

七、通信方式对比总结

父子直接通信 → Props / Emit 跨多层级透传 → provide / inject 兄弟/无关联组件 → mitt 或 Pinia 全局共享状态 → Pinia 基础 UI 组件 → 全局注册 业务页面组件 → 局部注册 + 异步加载

八、面试聚焦

8.1 Props 单向数据流

// 子组件不能直接修改 props// 应通过 emit 通知父组件修改emit('update:count',newValue)

8.2 provide/inject 响应式

// 默认不是响应式// 需要传递 ref 或 reactiveprovide('theme',ref('dark'))

8.3 全局注册无法 Tree-shaking

// 全局注册的组件即使未使用也会被打包// 业务组件应局部注册,支持 Tree-shaking

8.4 Vue 3 事件总线

// Vue 3 移除 $on/$off/$emit// 使用 mitt 库实现事件总线

九、易混淆点

  1. Props 是单向数据流:子组件不能直接修改 prop,应通过 emit 通知父组件。
  2. provide/inject 默认非响应式:传递refreactive才能实现响应式更新。
  3. mitt vs Pinia:mitt 适合一次性通知,Pinia 适合需要持久化的全局状态。
  4. 全局注册无法 Tree-shaking:未使用的全局组件仍会打包,业务组件应局部注册。
  5. defineProps / defineEmits:编译器宏,无需导入,不能在条件语句中使用。

十、思考与练习

1.Vue 组件通信有哪些方式?各自适用场景?

解析:

  • Props/Emit:父子直接通信
  • provide/inject:跨层级(主题、表单上下文)
  • mitt:兄弟或无关联组件
  • Pinia:全局共享状态

2.为什么子组件不能直接修改 props?

解析:Vue 遵循单向数据流,props 由父组件控制。子组件修改 props 会破坏数据流的可预测性,应通过 emit 通知父组件修改。

3.provide/inject 如何实现响应式?

解析:传递refreactive对象,而不是普通值:

provide('count',ref(0))// ✅ 响应式provide('count',0)// ❌ 非响应式

4.Vue 3 如何实现事件总线?

解析:使用 mitt 库替代 Vue 2 的$on/$off/$emit

importmittfrom'mitt'constbus=mitt()bus.on('event',handler)bus.emit('event',data)

5.全局注册和局部注册如何选择?

解析:

  • 全局注册:基础通用组件(Button、Input),减少重复导入
  • 局部注册:业务组件,依赖清晰,支持 Tree-shaking

总结

  • Props/Emit:父子通信,单向数据流,v-model 是其语法糖
  • provide/inject:跨层级通信,传递 ref/reactive 实现响应式
  • mitt:Vue 3 事件总线,替代o n / on/on/off
  • Pinia:全局状态管理,适合登录态、购物车等
  • 组件注册:全局(通用 UI)vs 局部(业务组件)vs 异步(按需加载)
http://www.jsqmd.com/news/1025015/

相关文章:

  • 2026年 非晶磁环厂家推荐榜单:快脉冲非晶磁环/核聚变非晶磁环/高精度磁环源头厂商深度测评 - 品牌发掘
  • 2026嘉兴黄金回收达人亲测:走访20店,整理出这份靠谱名单 - 商业信息快查
  • 2026年好用的视频去水印软件,视频去水印软件推荐合集
  • 去三亚点海鲜外卖怎样能点到便宜的?本地土著亲测省钱攻略快收好 - 资讯焦点
  • VisualCppRedist AIO:3分钟解决Windows软件运行问题的终极方案
  • 东北大学工商管理学院王牌专业有哪些?双学位项目就业前景详解 - 品牌2026
  • AI Agent 评估:怎么判断你的智能体到底好不好用?
  • 2026年展台搭建公司TOP10推荐:高级创意/简约稳固/大型小型展位展台设计搭建匠心精选,标杆品牌与靠谱服务深度解析! - 品牌发掘
  • java:变量与运算符
  • 候车厅人数统计管控智慧解决方案
  • 天津口碑雅思机构排行 2026:海归湾/环球雅思/新航道/朗阁/启德考培对比 - 资讯焦点
  • AI算法赋能烫金纸分切机:从机械裁切到智能决策的跨越
  • 2026年深圳合模机工厂排行:高精度、高效合模机源头厂家实力与口碑深度评测 - 品牌发掘
  • 电动车托运哪家最好最便宜?电动车托运哪家最划算?省钱寄送全攻略 - 快递物流资讯
  • 行业公认!2026 厦门黄金回收口碑 TOP 榜单,正规门店全收录 - 奢侈品回收评测
  • 终极指南:5分钟掌握Marketch,让Sketch设计秒变可测量网页
  • 兴城吃海鲜不踩雷!本地人强推「敬友海鲜饭店」,兴城旅游吃海鲜,就选口碑好的! - 资讯焦点
  • 北京带GPU扩展工控机品牌排行 实测适配能力对比 - 奔跑123
  • 全屋定制避坑十点细节 - 资讯焦点
  • 2026最新B站字幕导出保姆级教程:手把手教你一键提取字幕
  • Gemini 3.5 Flash:架构级优化的本地大模型推理新范式
  • 低龄/硕博通用!新加坡留学中介机构哪个比较好?2026靠谱机构汇总 - 资讯纵览
  • 明日方舟终极自动化助手:3分钟快速上手的一键长草解决方案
  • 三菱重工海尔中央空调全国售后服务电话24小时推出维修人工客服受理热线中心 - 资讯焦点
  • 5分钟掌握DeepMosaics:智能马赛克处理终极指南
  • 暑期旅游当地美食外卖攻略:美团一折活动帮你省出景点门票钱 - 资讯焦点
  • 临床执业医师老师推荐:别再追“明星讲师”了,系统师资才靠谱 - 医考机构品牌测评专家
  • 卖黄金别盲目比价!2026 厦门黄金回收精选榜单,透明靠谱商家汇总 - 奢侈品回收评测
  • Gemini 2.5 Flash Lite 高效落地实战指南
  • 北京迷你仓哪个品牌好?6个维度对比帮你选 - 速递信息