Vue组件事件规范要求:事件名用kebab-case(如submit-form)、参数用单对象、必须显式声明defineEmits类型、emit需在异步完成后再触发,确保类型安全与状态准确。

团队里统一 $emit 的用法,核心不是定一堆规则让人背,而是让命名和传参方式自然“不犯错”——靠约定 + 工具约束 + 少数关键检查点。
事件名必须用短横线格式(kebab-case)
所有自定义事件名写成 小写字母+短横线,比如 submit-form、update-user、close-dialog。不用驼峰(submitForm)、不用下划线(submit_form)、更不能和原生事件同名(如 click、input)。
原因很实际:Vue 模板中监听时是 HTML 属性语法,不区分大小写;@submitForm 会被当成 @submitform,和子组件 emit 的 submitForm 对不上,静默失败。
- 统一在组件文档或 README 中列出该组件支持的事件名,例如:
“支持事件:init-done、item-click、error-report” - CI 流程中加 ESLint 规则,对
emit(后面的字符串字面量做正则校验,不匹配/^[a-z]+(-[a-z]+)*$/就报错
参数传递优先用单个对象,少用多参数
子组件触发时写 emit('user-update', { id, name, avatar }),而不是 emit('user-update', id, name, avatar)。
对象传参的好处是:字段语义明确、顺序不敏感、TypeScript 类型好定义、后续加字段不影响父组件调用。
- 在
defineEmits中显式声明类型,比如:const emit = defineEmits({ 'user-update': (payload: { id: number; name: string }) => true }) - 父组件接收也直接解构:
@user-update="({ id, name }) => userId = id"或@user-update="handleUserUpdate",方法里再取payload.id - 只有两个以内简单参数(如
id和confirmed: boolean)且结构极稳定时,才考虑多参数写法
事件必须显式声明,禁用隐式 emit
setup 语法中,不写 defineEmits 就不准调用 emit。这不是可选项,是强制项。
好处有三:TypeScript 能校验事件名和参数类型、IDE 自动补全事件列表、运行时如果 emit 了未声明的事件,开发环境会警告(Vue 提供了 emits 选项的校验开关)。
- 组件开头统一加:
const emit = defineEmits(['submit-form', 'cancel-edit', 'validate-fail'])
或带类型版本(推荐) - Code Review 时重点看:有没有漏声明、有没有拼错事件名、有没有把
update:modelValue写成updateModelValue - 禁止在模板中直接写
@submit-form="doSomething"却不在子组件里声明submit-form事件
关键时机要对齐:emit 前数据必须就绪
emit 不是“我点了按钮”,而是“我确认这事完成了”。常见错误是在异步操作前就 emit,比如:
- ❌ 错误:点击后立刻
emit('save'),然后才await api.save()→ 父组件收到事件时,数据还没存 - ✅ 正确:等请求成功(或失败)回调里再
emit('save-success', result)或emit('save-error', err) - 表单类组件建议拆成多个事件:
submit-start、submit-success、submit-error,比只用一个submit更易追踪状态


















