父组件处理 vue 3 emits 的核心是监听、响应与状态同步:需用 @ 精确匹配子组件 defineemits 声明的事件名,参数通过 $event 传递或结构化对象封装,更新自身响应式数据而非修改传入值,并推荐 typescript 类型声明保障安全。

父组件接收和处理 Vue 3 的 emits 事件,关键在于“监听 + 响应 + 更新”,不是被动收数据,而是主动绑定行为、解构参数、同步状态。下面从实际开发中最常踩坑的环节讲清楚。
监听事件必须用 @ 符号,且名称要和子组件 defineEmits 中声明的一致
子组件定义了哪些事件,父组件才能监听哪些。比如子组件写了:
const emit = defineEmits(['update:count', 'submit'])
那父组件就必须用 @update:count 或 @submit,不能写成 @updateCount 或 @onSubmit——Vue 不做自动转换,拼错就静默失效。
- 推荐统一用
update:xxx格式,这样配合v-model可以自动映射(如v-model:count="fansCount"等价于@update:count="fansCount = $event") - 如果子组件用的是普通事件名(如
'click-outside'),父组件就直接写@click-outside,注意中划线命名需用短横线形式
接收参数:$event 是默认载体,多参数需结构化处理
子组件调用 emit('submit', data, extra) 时,父组件监听函数会收到一个参数列表,但 Vue 默认只把第一个额外参数赋给 $event。所以:
- 单参数最简单:
@submit="handleSubmit"→function handleSubmit(payload) { ... },payload就是data - 多参数建议打包成对象传递:
emit('submit', { user, timestamp }),避免顺序依赖和类型混乱 - 若真要传多个独立值,父组件需用箭头函数或解构:
@submit="(a, b) => handleMulti(a, b)",但不推荐,可读性差且 TypeScript 难约束
响应逻辑要明确更新来源,避免和 props 冲突
父组件接收到事件后,通常要更新自己的响应式变量。但要注意:
- 不要直接改子组件传来的值(比如
payload.count++),那是临时对象,改了也没用 - 应该更新父组件自己的 ref 或 reactive 数据:
count.value = payload.newCount或state.count = payload.count - 如果这个值也作为 props 传回子组件(比如表单校验后反馈状态),记得子组件要用
v-model或:status.sync(已废弃)等机制接收,否则视图不会重绘
类型安全建议:用类型声明约束 emits 参数
在 TypeScript 项目中,别只用字符串数组声明 defineEmits(['save'])。更稳妥的是:
const emit = defineEmits()
- 这样父组件写
@save="handleSave"时,IDE 能提示handleSave必须接收一个对象参数,减少运行时错误 - Vue 3.3+ 还支持更简洁的写法:
defineEmits() - 类型声明还能让
$event在模板中获得正确推导(比如@save="data => console.log(data.id)"中data有完整类型)
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










