在 Vue 中,子组件获取父组件在其上绑定的事件,通常有两种场景:透传事件到子组件内部元素 或 在子组件逻辑中手动触发父组件事件。:
Vue 2 中的实现
1. 透传事件到子组件内部元素
使用 $listeners
将父组件绑定的事件传递给子组件内部元素:
<!-- 父组件 Parent.vue -->
<template>
<Child @click=handleClick @custom-event=handleCustom />
</template>
<script>
export default {
methods: {
handleClick() { console.log('父组件的点击事件'); },
handleCustom() { console.log('父组件的自定义事件'); }
}
}
</script>
<!-- 子组件 Child.vue -->
<template>
<!-- 将父组件的事件绑定到内部按钮 -->
<button v-on=$listeners>点击触发所有事件</button>
</template>
2. 在子组件逻辑中手动触发事件
通过 this.$emit(eventName)
触发父组件事件:
<!-- 子组件 Child.vue -->
<template>
<button @click=triggerEvents>点击手动触发事件</button>
</template>
<script>
export default {
methods: {
triggerEvents() {
this.$emit('click'); // 触发父组件的 @click
this.$emit('custom-event'); // 触发父组件的 @custom-event
}
}
}
</script>
Vue 3 中的实现
1. 透传事件到子组件内部元素
使用 v-bind="$attrs"
(Vue 3 中事件和属性合并到 $attrs
):
<!-- 父组件 Parent.vue -->
<template>
<Child @click=handleClick @custom-event=handleCustom />
</template>
<script setup>
const handleClick = () => console.log('父组件的点击事件');
const handleCustom = () => console.log('父组件的自定义事件');
</script>
<!-- 子组件 Child.vue -->
<template>
<!-- 将父组件的事件绑定到内部按钮 -->
<button v-bind=$attrs>点击触发所有事件</button>
</template>
2. 在子组件逻辑中手动触发事件
通过 emit
函数触发事件(需声明 emits
):
<!-- 子组件 Child.vue -->
<template>
<button @click=triggerEvents>点击手动触发事件</button>
</template>
<script setup>
import { defineEmits } from 'vue';
// 声明组件支持的事件
const emit = defineEmits(['click', 'custom-event']);
const triggerEvents = () => {
emit('click'); // 触发父组件的 @click
emit('custom-event'); // 触发父组件的 @custom-event
};
</script>
关键区别
功能 | Vue 2 | Vue 3 |
---|---|---|
事件对象 | $listeners |
合并到 $attrs |
事件声明 | 无显式声明 | 需通过 defineEmits 声明 |
触发事件方法 | this.$emit(eventName) |
emit(eventName) |
透传事件 | v-on="$listeners" |
v-bind="$attrs" |
场景示例
场景 1:透传原生事件
父组件绑定 @click
(原生事件),子组件内部元素响应点击:
<!-- 父组件 -->
<Child @click=handleClick />
<!-- 子组件 Child.vue (Vue 3) -->
<template>
<!-- 将点击事件绑定到内部 div -->
<div class=wrapper v-bind=$attrs>
<p>点击此区域触发父组件的点击事件</p>
</div>
</template>
场景 2:手动触发多个事件
子组件在异步操作完成后触发父组件事件:
<!-- 子组件 Child.vue (Vue 3) -->
<script setup>
import { defineEmits } from 'vue';
const emit = defineEmits(['success', 'error']);
const fetchData = async () => {
try {
await api.getData();
emit('success'); // 触发父组件的 @success
} catch (err) {
emit('error', err); // 触发父组件的 @error 并传递错误对象
}
};
</script>
总结
- 透传事件:直接将父组件的事件绑定到子组件内部元素(通过
$listeners
或$attrs
)。 - 手动触发:在子组件逻辑中通过
$emit
/emit
方法触发事件。 - Vue 3 注意:使用
defineEmits
声明事件,提高代码可读性和类型安全。