Vue组件通信必须遵循官方机制:父子用defineProps/defineEmits并注意响应式规则;跨层级用provide/inject配合ref和监听;兄弟用Pinia;非关系组件用mitt事件总线并及时销毁监听。
☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 多模态理解力帮你轻松跨越从0到1的创作门槛☜☜☜

在Cursor中写Vue项目时,组件通信必须按Vue官方机制实现,不能依赖Cursor的AI自动补全来生成通信逻辑,否则容易写出违反单向数据流或破坏响应式的行为。
父子组件通信:用defineProps和defineEmits
在<script setup>语法下,父组件传值必须通过属性绑定,子组件接收必须显式声明defineProps。</script>
第一步:在子组件顶部声明props接收规则,类型必须精确——比如字符串用String,数组用Array,对象用Object,且引用类型默认值必须是工厂函数:【default: () => []】,否则会引发所有实例共享同一数组的bug。
第二步:父组件使用v-bind动态绑定,不要写成字面量静态赋值,例如
立即学习“前端免费学习笔记(深入)”;
第三步:子组件触发事件必须先用defineEmits声明事件名,再调用emit,未声明的事件名在开发模式下会直接报错。
跨层级方法传递:provide/inject配合ref
当需要从根组件向深层孙子组件传递一个可调用的方法(如全局登出),不能靠层层props透传。
方法一:祖先组件provide时,把方法包裹进ref或reactive里——因为provide默认不响应,直接provide一个普通函数,后代组件拿到后即使祖先方法内部逻辑变了,后代也感知不到更新。
方法二:后代组件inject后,必须用onBeforeMount或watchEffect监听该注入值变化,否则首次渲染可能拿到undefined。
这一步操作起来很简单,直接把文件拖进去就行。
兄弟组件通信:用Pinia统一状态
Cursor对Pinia的类型推导支持很好,推荐在store目录下新建useUserStore.ts,定义state、actions和getters。
在任意兄弟组件中,import { useUserStore } from '@/stores/user' → const store = useUserStore() → 直接读写store.token或调用store.logout()。
注意:不要在store里直接调用this.$router或this.$message,这些属于组件实例API,Pinia store应保持纯逻辑。
非关系组件通信:用自定义事件总线(仅Vue 2)或mitt(Vue 3)
Vue 3项目禁用EventBus(基于Vue实例),改用轻量库mitt。
执行npm install mitt → 创建eventBus.ts:import { createEventHub } from 'mitt' → export const bus = createEventHub()。
发送方:bus.emit('dialog-close', { id: 123 })。
接收方:bus.on('dialog-close', handler),且必须在onUnmounted中调用bus.off('dialog-close', handler)清除监听,【否则内存泄漏】。


















