P粉1229324662023-08-31 00:50:39
After browsing the Vue3 source code, there is no way to provide
specifications directly in the template to dynamic components
. It must be called in the settings function or options of the parent hosting the dynamic component, or in the settings or options of the dynamic component.
The two options are:
provide
on the component that hosts the dynamic component. setup() { provide('message', 'hello') }
<template> <component :is='myComponent' /> </template>
This doesn't work for me because my setter function is called before my dynamic component is activated; I also need the component type to be set along with the provided value.
function setComponent(someImportedComponent, providedValues) { myComponent.value = someImportedComponent myProps.value = { toProvide: providedValues } }
<template> <component :is='myComponent' v-bind='myProps' /> </template>
My component
setup() { for(let [key,value] of Object.entries(props.toProvide) ) { provide(key, value) } }
Now this has its problems, as each dynamic component now needs to be responsible for understanding and calling the incoming provider.
The solution to each component needing to know the value provided is to create an intermediate component that provides the value.
Available (intermediate components)
<script setup lang="ts"> import {provide} from 'vue' const props = defineProps<{ is: any provide?: Record<string, any> [key: string]: any }>() if (props.provide) { for (const [key, value] of Object.entries(props.provide)) { provide(key, value) } } const _props = Object.fromEntries(Object.entries(props).filter(it => { return it[0] !== 'is' && it[0] !== 'provide' })) </script> <template> <component :is="is" v-bind="_props"/> </template>
Use it like this:
<template> <providable :is="myComponent" :provide='toProvide' v-bind='myProps' /> </template>
A cleaner solution is to create a wrapper component, similar to how keep-alive works. The target component only needs to be put into the default slot
.
Provide.vue
<script setup lang="ts"> import {provide} from 'vue' const props = defineProps<{ value: Record<string, any> }>() for (const [key, value] of Object.entries(props.value)) { provide(key, value) } </script> <template> <slot name="default"/> </template>
and use it like this:
<template> <provide value='toProvide'> <my-component v-bind='myProps' /> </provide> </template>