emit 本身不默认触发任何事件,它只是 vue 提供的手动抛出事件机制;所有事件(包括原生和自定义)都需子组件显式监听并调用 emit 才能向父组件传递,且推荐使用语义化 kebab-case 事件名并显式声明。

Emit 本身不默认触发任何事件,它只是 Vue 提供的“手动抛出事件”的机制。所谓“默认事件”并不存在——无论是原生 DOM 事件(如 click、input)还是自定义业务事件(如 submit-form、update-search),都必须由子组件显式监听 + 显式调用 emit 才能向父组件传递。
原生 DOM 事件不能直接被父组件 @click 监听
给自定义组件写 @click="handler" 默认不会响应,因为组件不是原生元素,没有内置 click 行为。此时有两条路径:
- 加
.native修饰符(Vue 2):让事件绑定到子组件的根元素上,触发的是真实 DOM 冒泡,不是 $emit,也不经过子组件逻辑 - Vue 3 中已移除
.native,需在子组件模板根元素上手动绑定@click,再在回调里emit('click')——但注意:这仍是自定义事件,名字叫click容易混淆,不推荐
正确做法:用 emit 封装语义化业务事件
不要把 click 当业务逻辑,而应表达“用户做了什么”:
- 子组件中监听原生事件:
<button></button> - 方法内调用
emit('form-submit', formData)(Vue 3 Composition API)或this.$emit('form-submit', formData)(Vue 2) - 父组件监听:
<myform></myform>,接收参数即formData,不接触原生event对象
事件命名与声明建议
提升可维护性,避免歧义:
- 事件名统一用 kebab-case(如
user-login、item-removed),不使用驼峰或大驼峰 - Vue 3 推荐在子组件中用
defineEmits(['user-login', 'item-removed'])显式声明,支持类型校验和 IDE 提示 - 避免用原生事件名(如
click、change)作自定义事件名,否则可能和inheritAttrs透传行为冲突
什么时候会“自动”触发?只有透传场景
如果子组件根元素是普通 HTML 标签(如 <div>),且未设置 <code>inheritAttrs: false,父组件绑定的原生事件(如 @click)会自动“透传”到该根元素上——但这和 emit 无关,是 Vue 的 attribute 继承机制,属于 DOM 层行为,父组件拿不到子组件内部状态。










