在Vue 3的组件化开发体系里,组件之间的通信是构建复杂应用的基础能力,其中子组件向父组件传递事件并控制父组件状态是非常常见的需求,自定义事件就是实现这一需求的核心方案。

自定义事件的核心原理
Vue 3的自定义事件基于发布订阅模式实现,子组件通过emit方法触发自定义事件,父组件在引用子组件时监听对应的自定义事件,当事件触发时执行父组件中定义的处理函数,从而修改父组件的状态或者执行相关逻辑。
子组件触发自定义事件
在Vue 3的<script setup>语法中,需要先通过defineEmits定义要触发的事件列表,再调用返回的emit函数触发事件。如果是选项式API,则可以直接通过this.$emit触发事件。
组合式API(<script setup>)示例
下面是一个计数器子组件的示例,子组件内部有一个按钮,点击按钮时触发自定义事件,向父组件传递最新的计数值:
<template>
<div class="child-component">
<p>子组件当前计数:{{ count }}</p>
<button @click="handleIncrement">点击增加计数</button>
</div>
</template>
<script setup>
import { ref } from 'vue'
// 定义要触发的自定义事件,数组中的字符串就是事件名称
const emit = defineEmits(['update-count'])
const count = ref(0)
const handleIncrement = () => {
count.value++
// 触发自定义事件,第二个参数及之后的内容都是传递给父组件的参数
emit('update-count', count.value)
}
</script>
选项式API示例
如果是使用选项式API开发子组件,触发事件的方式如下:
<template>
<div class="child-component">
<button @click="handleClick">触发事件</button>
</div>
</template>
<script>
export default {
data() {
return {
message: '子组件传递的信息'
}
},
methods: {
handleClick() {
// 直接通过this.$emit触发事件
this.$emit('custom-event', this.message)
}
}
}
</script>
父组件监听自定义事件
父组件在使用子组件时,通过v-on或者@语法监听子组件触发的自定义事件,事件触发时执行对应的处理函数,在处理函数中可以修改父组件自身的状态。
以下是父组件的示例代码,引用上面的计数器子组件,监听update-count事件并更新父组件的计数状态:
<template>
<div class="parent-component">
<p>父组件接收的计数:{{ parentCount }}</p>
<!-- 监听子组件的update-count事件,执行handleUpdateCount函数 -->
<ChildComponent @update-count="handleUpdateCount" />
</div>
</template>
<script setup>
import { ref } from 'vue'
import ChildComponent from './ChildComponent.vue'
const parentCount = ref(0)
const handleUpdateCount = (newCount) => {
// 将子组件传递过来的新计数值赋值给父组件的状态
parentCount.value = newCount
}
</script>
自定义事件的参数传递规则
子组件触发emit时,除了事件名称之外,可以传递多个参数给父组件,父组件的事件处理函数按照顺序接收这些参数即可。
比如子组件触发事件时传递两个参数:
// 子组件中触发事件,传递两个参数
emit('change-data', '新名称', 18)
父组件的处理函数对应接收:
// 父组件中处理函数接收两个参数
const handleChangeData = (name, age) => {
console.log(name, age) // 输出 新名称 18
}
常见注意事项
- 事件名称推荐使用kebab-case(短横线分隔)命名,虽然Vue 3支持 camelCase,但HTML模板中大小写不敏感,使用kebab-case可以避免兼容性问题。
- 如果使用
defineEmits定义了事件列表,那么触发未定义的事件时Vue会抛出警告,建议提前定义好所有要触发的事件,提升代码的可维护性。 - 不要在子组件中直接修改父组件传递的props,自定义事件的核心作用就是让父组件自行修改状态,遵循单向数据流原则。
常见问题排查
如果自定义事件无法触发,可以按照以下步骤排查:
- 检查子组件中
emit的事件名称是否和父组件监听的事件名称完全一致,包括大小写和分隔符。 - 检查父组件监听事件时是否写错了事件名称,或者没有正确引入子组件。
- 如果是组合式API,检查是否忘记了调用
defineEmits就直接使用emit,这种情况会导致emit未定义报错。