Vue 3 组件通讯的 4 种准确姿势 [复制链接]
发表于 2026-3-4 12:54:49 | 显示全部楼层 |阅读模式
🧑‍💻 写在开头

点赞 + 收藏 === 学会🤣🤣🤣
上个月,我们重构一个老项目,发现一个“祖传组件”:

  • 父组件传 props 给子组件
  • 子组件再传给孙子
  • 孙子改了个状态,通过 $emit 一层层往上抛
  • 中央恣意一层改名,整条链就断了……
同事苦笑:“这哪是组件通讯,这是传话游戏。”
实在,Vue 3 早就提供了更优雅、更坚固的通讯方案。
本日我就用 4 种场景 + 对应解法,帮你彻底告别“props drilling”和“emit 地狱”。
先看一张决定图(发起收藏)


 
注意:不是全部通讯都要用 Pinia! 小范围状态用轻量方案更干净。
姿势 1:父子通讯 —— 老诚实实用 props/emit(但要规范)

这是最底子的,但许多人写得乱:
反面课本:
  1. [/code]准确做法:单一职责 + 语义化定名
  2. [code]
复制代码
本领:用 v-model 代替自界说 update-xxx,模板更轻便:
  1. [/code][size=5]姿势 2:祖孙通讯 —— 用 provide / inject 跳过中央层[/size]
  2. 当你须要从 App.vue 直接传数据到深度嵌套的 Button 组件,别再层层传 props!
  3. [code]// App.vue
  4. import { provide, ref } from 'vue';
  5. const theme = ref<'light' | 'dark'>('light');
  6. provide('THEME', theme); // 提供响应式数据
复制代码
  1. <template>
  2.   <button :>Click me</button>
  3. </template>
复制代码
  关键点:

  • 如果 provide 的是 ref 或 reactive,inject 拿到的就是相应式的
  • 可以共同 TypeScript 界说 InjectionKey,克制字符串邪术值
  1. // types.ts
  2. import { InjectionKey, Ref } from 'vue';
  3. export const THEME_KEY: InjectionKey<Ref<'light' | 'dark'>> = Symbol('theme');
复制代码
姿势 3:恣意组件通讯 —— 用 Composable 封装共享状态(90% 的人不知道!)

这是 Vue 3 最被低估的本事!
想象:两个不相干的弹窗,须要共享“是否正在提交”状态
错误做法:把状态提到父组件,或滥用 Pinia
准确做法:写一个 useSubmitState composable:
  1. // composables/useSubmitState.ts
  2. import { ref } from 'vue';
  3. const isSubmitting = ref(false);
  4. export function useSubmitState() {
  5.   const start = () => isSubmitting.value = true;
  6.   const end = () => isSubmitting.value = false;
  7.   return { isSubmitting, start, end };
  8. }
复制代码
然后在恣意组件中利用:
  1. [/code][code]
复制代码
  上风:

  • 零依赖(不消 Pinia)
  • 天然相应式
  • 可测试、可复用
  • 作用域清晰(只在须要的组件引入)
姿势 4:全局状态 —— 交给 Pinia,别本身造轮子

当状态涉及:

  • 用户登录信息
  • 全局主题/语言
  • 跨路由的数据缓存
这时间就该用 Pinia(Vuex 的继任者,Vue 官方保举):
  1. // stores/user.ts
  2. import { defineStore } from 'pinia';
  3. export const useUserStore = defineStore('user', () => {
  4.   const profile = ref(null);
  5.   const isLoggedIn = computed(() => !!profile.value);
  6.   const login = async (credentials) => {
  7.     profile.value = await api.login(credentials);
  8.   };
  9.   return { profile, isLoggedIn, login };
  10. });
复制代码
在组件中:
  1. const userStore = useUserStore();
  2. userStore.login({ email, password });
复制代码
  Pinia 上风:

  • Composition API 风格
  • 完善 TS 支持
  • DevTools 调试友爱
  • 服务端渲染(SSR)兼容
总结:什么时间用哪种?


 不要:

  • 用 $parent / $children(粉碎封装)
  • 用 EventBus(Vue 3 已废弃)
  • 全部状态都塞进 Pinia(过分计划)
如果对您有所资助,接待您点个关注,我会定时更新技能文档,各人一起讨论学习,一起进步。



免责声明:如果侵犯了您的权益,请联系站长及时删除侵权内容,谢谢合作!qidao123.com:ToB企服之家,中国第一个企服评测及软件市场,开放入驻,技术点评得现金.

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表