组件事件
本页面默认你已经阅读过 组件基础。如果你是组件新手,请先阅读那一部分。
发出与监听事件
组件可以使用内置的 $emit 方法,直接在模板表达式中(例如在 v-on 处理器中)发出自定义事件:
template
<!-- MyComponent -->
<button @click="$emit('someEvent')">点我</button>然后父组件可以使用 v-on 来监听它:
template
<MyComponent @some-event="callback" />组件事件监听器也支持 .once 修饰符:
template
<MyComponent @some-event.once="callback" />和组件与 props 一样,事件名会自动进行大小写转换。注意我们发出了一个 camelCase 事件,但在父组件中可以使用 kebab-case 的监听器来监听它。与 props 的大小写规范 一样,我们建议在模板中使用 kebab-case 的事件监听器。
TIP
不同于原生 DOM 事件,组件发出的事件不会冒泡。你只能监听直接子组件发出的事件。如果需要在兄弟组件或深层嵌套组件之间通信,请使用外部事件总线或 全局状态管理方案。
事件参数
有时,随事件一起发出一个特定值会很有用。例如,我们可能希望 <BlogPost> 组件负责决定将文本放大多少。在这种情况下,我们可以向 $emit 传入额外参数来提供这个值:
template
<button @click="$emit('increaseBy', 1)">
增加 1
</button>然后,当我们在父组件中监听该事件时,可以使用内联箭头函数作为监听器,这样就能访问事件参数:
template
<MyButton @increase-by="(n) => count += n" />或者,如果事件处理器是一个方法:
template
<MyButton @increase-by="increaseCount" />那么该值将作为这个方法的第一个参数传入:
js
function increaseCount(n) {
count.value += n
}TIP
传给 $emit() 的所有额外参数都会在事件名之后传递给监听器。例如,使用 $emit('foo', 1, 2, 3) 时,监听函数会接收到三个参数。
声明发出的事件
组件可以使用 defineEmits() 宏显式声明它将发出的事件:
vue
<script setup>
defineEmits(['inFocus', 'submit'])
</script>我们在 <template> 中使用的 $emit 方法在组件的 <script setup> 部分中无法直接访问,但 defineEmits() 会返回一个等价的函数供我们替代使用:
vue
<script setup>
const emit = defineEmits(['inFocus', 'submit'])
function buttonClick() {
emit('submit')
}
</script>defineEmits() 宏不能在函数内部使用,它必须像上面的示例那样直接放在 <script setup> 中。
如果你使用的是显式的 setup 函数而不是 <script setup>,则应使用 emits 选项来声明事件,并且 emit 函数会暴露在 setup() 上下文中:
js
export default {
emits: ['inFocus', 'submit'],
setup(props, ctx) {
ctx.emit('submit')
}
}与 setup() 上下文的其他属性一样,emit 也可以安全地被解构:
js
export default {
emits: ['inFocus', 'submit'],
setup(props, { emit }) {
emit('submit')
}
}emits 选项和 defineEmits() 宏也支持对象语法。如果使用 TypeScript,你可以为参数添加类型,这使我们能够在运行时验证已发出事件的负载:
vue
<script setup lang="ts">
const emit = defineEmits({
submit(payload: { email: string, password: string }) {
// 返回 `true` 或 `false` 以表示
// 校验通过 / 失败
}
})
</script>如果你在 <script setup> 中使用 TypeScript,也可以使用纯类型注解来声明发出的事件:
vue
<script setup lang="ts">
const emit = defineEmits<{
(e: 'change', id: number): void
(e: 'update', value: string): void
}>()
</script>更多细节:组件发出事件的类型标注
虽然不是必需的,但仍建议定义所有发出的事件,以便更好地记录组件应如何工作。这样 Vue 还可以将已知监听器从 透传 Attribute 中排除,避免由第三方代码手动派发 DOM 事件所导致的边缘情况。
TIP
如果在 emits 选项中定义了原生事件(例如 click),那么监听器现在只会监听组件发出的 click 事件,不再响应原生的 click 事件。
事件校验
与 props 的类型校验类似,如果使用对象语法而不是数组语法来定义事件,那么发出的事件也可以被校验。
要添加校验,需要为该事件赋值一个函数,该函数接收传给 emit 调用的参数,并返回一个布尔值来表示该事件是否有效。
vue
<script setup>
const emit = defineEmits({
// 无校验
click: null,
// 校验 submit 事件
submit: ({ email, password }) => {
if (email && password) {
return true
} else {
console.warn('无效的 submit 事件负载!')
return false
}
}
})
function submitForm(email, password) {
emit('submit', { email, password })
}
</script>