我们正在创建一个应用程序,其中接口基于 API 返回的 JSON 动态安装。它看起来像这样:
{
"path": "Container",
"children": [
{
"slot": "default",
"path": "Banner",
"props": {
"items": [ "image1.jpg", "image2.jpg", "image3.jpg" ]
}
},
{
"slot": "header",
"path": "Flex",
"props": {
"flow": "row"
},
"children": [
{
"slot": "default",
"path": "Icon",
"props": {
"name": "mdi-forum"
}
},
{
"slot": "default",
"text": "Example of title"
}
]
}
]
}
所以我ComponentLoader
用computed
做一个动态创建了一个动态import
,然后我还根据需要递归地注入更多的动态组件加载器,使用一个v-for
通过children
列表:
<template>
<component v-if="component" :is="component" v-bind="$attrs">
<template v-for="(child, i) of children">
<ComponentLoader
v-if="child.path"
v-bind="child.props"
:key="`${child.path}-${i}`"
:path="child.path"
:children="child.children"
/>
<template v-else>{{ child.text || '' }}</template>
</template>
</component>
</template>
<script>
import Error from '~/components/ComponentLoaderError.vue'
export default {
name: 'ComponentLoader',
components: { Error },
props: {
path: { type: String, required: true },
children: { type: Array, default: () => [] },
},
computed: {
component() {
if (!this.path) return null
return () => import(`~/components/${this.path}`).then((m) => m || m.default).catch(() => Error)
},
},
}
</script>
它几乎可以工作了,但是所有孩子都被注入到每个加载组件的默认插槽中,这很有意义,因为我没有在通过孩子的循环期间通知所需的插槽。
受到这个答案的启发,我在with上添加了一个v-slot
绑定,使用动态插槽名称注入基于已从 JSON 接收的属性的正确插槽:<template>
v-for
child.slot
<template v-for="(child, i) of children" #[child.slot]>
对于每个插槽上只有一个子节点的节点,它按预期工作。但是当我有更多的孩子要分布在同一个插槽中时(比如那个 JSON 中的最后一个孩子数组),只有最后一个孩子被注入,之前覆盖了其他孩子。
那么,如何在循环中将许多子节点注入到动态命名槽中?