Reputation: 2372
I'd like in Vue 3 to be able to provide/overwrite existing components to slots by doing something like:
<ProvideFun>
<p>
Hello
<FunA></FunA>
</p>
</ProvideFun>
<ProvideOtherFun>
<p>
Hello
<FunA></FunA>
</p>
</ProvideOtherFun>
in order to be allowed to use some components (here <FunA>
) inside others components (here <ProvideFun>
and <ProvideOtherFun>
). Note that ProvideFun
and ProvideOtherFun
may provide different versions of the <FunA>
component.
How could I do something like that?
You can find a demo here.
Upvotes: 0
Views: 1159
Reputation: 138226
The parent (i.e., ProvideFun
or ProvideOtherFun
) could provide
its own component definition (named "comp"
) to be used in FunA
:
<!-- ProvideFun.vue -->
<script setup>
import { provide } from 'vue'
import CompA from './CompA.vue'
👇
provide('comp', CompA)
</script>
<template>
<h1>
Provide fun
</h1>
<slot />
</template>
<!-- ProvideOtherFun.vue -->
<script setup>
import { provide } from 'vue'
import CompB from './CompB.vue'
👇
provide('comp', CompB)
</script>
<template>
<h1>
Provide other fun
</h1>
<slot />
</template>
Make FunA.vue
a <component>
wrapper that inject
s the "comp"
component definition from a parent:
<!-- FunA.vue -->
<script setup>
import { inject } from 'vue'
👇
const comp = inject('comp')
</script>
<template> 👇
<component :is="comp" />
</template>
This requires registering the FunA
placeholder component before it could be used in ProvideFun
/ProvideOtherFun
:
<script setup>
import ProvideFun from './ProvideFun.vue'
import ProvideOtherFun from './ProvideOtherFun.vue'
👇
import FunA from './FunA.vue'
</script>
<template>
<ProvideFun>
<p>
Hello
<FunA />
</p>
</ProvideFun>
<ProvideOtherFun>
<p>
Hello
<FunA />
</p>
</ProvideOtherFun>
</template>
Bind the CompA
component definition as a slot prop (named "FunA"
) in ProvideFun.vue
, and CompB
in ProvideOtherFun.vue
:
<!-- ProvideFun.vue -->
<script setup>
import CompA from './CompA.vue'
</script>
<template> 👇
<slot :FunA="CompA">
</template>
<!-- ProvideOtherFun.vue -->
<script setup>
import CompB from './CompB.vue'
</script>
<template> 👇
<slot :FunA="CompB">
</template>
Then use a <component>
to render it in the parent:
<script setup>
import ProvideFun from './ProvideFun.vue'
import ProvideOtherFun from './ProvideOtherFun.vue'
</script>
<template>
<ProvideFun> 👇
<template v-slot="{ FunA }">
<p>
Hello 👇
<component :is="FunA" />
</p>
</template>
</ProvideFun>
<ProvideOtherFun> 👇
<template v-slot="{ FunA }">
<p>
Hello 👇
<component :is="FunA" />
</p>
</template>
</ProvideOtherFun>
</template>
Upvotes: 2