$event
只在「模板里的内联表达式」里有效,代表 本次事件携带的原始数据 ------
• 原生事件:浏览器 Event 对象
• 组件自定义事件:子组件 $emit
的第 2+ 个参数
【$emit( name, arg1, arg2, ... )
里的 第 2、3、4... 个参数 都会原封不动地 被 Vue 打包成一个类数组对象 (严格说就是普通参数列表),父组件模板里写 $event
时,拿到的就是这一个列表 ;如果你只关心第一个参数,那 $event
就等价于 arg1
】
使用场景总览
场景 | 绑定目标 | 触发源 | $event 内容 |
---|---|---|---|
1. 原生 DOM 事件 | <div @click> <input @input> |
浏览器 | Event |
2. 表单输入 v-model | <input v-model> |
浏览器 | Event |
3. 组件自定义事件 | <my-cpn @foo> |
子组件 $emit('foo', payload) |
payload |
4. 组件 v-model | <my-cpn v-model> |
子组件 $emit('input', payload) |
payload |
5. 原生事件 .native | <my-cpn @click.native> |
浏览器 | Event |
1. 原生 DOM 事件
vue
<template>
<button @click="log">点我</button>
</template>
<script>
export default {
methods: {
log (e) {
console.log('原生事件对象:', e) // $event 就是 MouseEvent
}
}
}
</script>
2.表单输入 v-model
vue
<template>
<!-- 手动拆解 v-model,暴露 $event -->
<input :value="msg" @input="msg = $event.target.value">
</template>
<script>
export default {
data () {
return { msg: '' }
}
}
</script>
3.组件自定义事件
父组件:CustomParent.vue
vue
<template>
<!-- $event 就是子组件 emit 的 payload -->
<counter @increment="total += $event"/>
</template>
<script>
import Counter from './Counter.vue'
export default {
components: { Counter },
data () { return { total: 0 } }
}
</script>
子组件:Counter.vue
vue
<template>
<button @click="$emit('increment', 2)">+2</button>
</template>
特别注意:Vue 2 的自定义事件($emit
)根本就不会自动冒泡 ,所以不存在"第三层还能不能拿到 payload"的问题------事件在第 1 层就被消费了,后面的层级默认收不到。
体系 | 是否冒泡 | 典型 API | 备注 |
---|---|---|---|
浏览器原生 DOM 事件 | ✅ 冒泡 | addEventListener 、.native |
点击、键盘、滚动... |
Vue 自定义事件系统 | ❌ 不冒泡 | vm.$emit 、组件 @foo |
只在父子之间点对点通信 |
想让"第三层"也能收到,有 3 种正规手段
- 逐层向上
$emit
每一层都$emit('custom', payload)
,像接力棒一样传上去。 - 中央事件总线 / Vuex
用new Vue()
做bus
或 Vuex 全局状态,跨 N 层随意通信。 .sync
语法糖 (Vue 2.3+)
逐层写:value.sync="val"
,Vue 会自动帮你每层都转发update:value
。