Forwarding of emits through intermediate components between parent/grandchild like in Svelte
What problem does this feature solve?
Svelte has this awesome feature, where you forward emits
through intermediate components between parent/grandchild.
This feature would help managing emits
, since components can get big and confusing, esp. with a lot of props/emits
being passed around.
What does the proposed API look like?
GrandChild.vue
:
<template>
<GrandChild @click=click/>
</template>
<script setup>
const emit = defineEmits([
'emitData'
])
const click = (data) => {
emit('emitData', data)
}
</script>
Child.vue
:
<template>
<Child @emitData>
</template>
or
<template>
<Child @emitData=$up>
</template>
or something more creative..., and it would be received by the parent just like it is now:
<template>
<Parent @emitData=getData/>
</template>
<script setup>
const getData = (data) => {
console.log(data)
}
</script>
I don't know for sure, but it seems like toHandlers
is what you need.
UPD: No, it doesnt work.
Here's a utility from shadcn-vue https://github.com/radix-vue/shadcn-vue/blob/ae81084f367b704615f6e6677c91cbae466c4978/apps/www/src/lib/utils.ts#L17-L34 that I've improved a bit and it works great for me.
import { camelize, getCurrentInstance, toHandlerKey } from "vue";
function useEmitAsProps<EventName extends string>(
emit: (name: EventName, ...args: any[]) => void
) {
const result: Record<string, any> = {};
const vm = getCurrentInstance();
if (!vm) return result;
const events: EventName[] = Array.isArray(vm.type.emits)
? vm.type.emits
: typeof vm.type.emits === "object"
? Object.keys(vm.type.emits)
: [];
if (!events.length) {
console.warn(
`No emitted event found. Please check component: ${vm.type.__name}`
);
}
for (let i = 0; i < events.length; i++) {
result[toHandlerKey(camelize(events[i]!))] = (...args: any) =>
emit(events[i]!, ...args);
}
return result;
}