i'm building a tab component where i need to pass component as a prop.
how can i display the component passed in the props?
Tab.vue
<template>
<div >
<button @click="activeTab = title" v-for="title in titles" v-text="title"
:/>
</div>
<div >
<component :is="activeTab"></component> // not working
</div>
</template>
<script setup>
import {onMounted, ref} from "vue";
const props = defineProps({
titles: {},
tabs: {}
})
const activeTab = ref("")
onMounted(() => {
activeTab.value = props.titles[0]
})
</script>
Settings.vue
<template>
<Tab :titles="[$t('languagesLabel'),$t('countriesLabel')]" :tabs="[Languages,Countries]">
</Tab>
</template>
<script setup>
import Tab from "../../components/admin/common/Tab.vue";
import Countries from "../../components/admin/settings/Countries.vue";
import Languages from "../../components/admin/settings/Languages.vue";
</script>
the question is how to make the displayed component dynamic ?
CodePudding user response:
You could use slot
to pass components instead of props :
<div >
<slot/>
</div>
in Settings.vue :
<template>
<Tab :titles="[$t('languagesLabel'),$t('countriesLabel')]" >
<Countries />
<Languages />
</Tab>
</template>
<script setup>
import Tab from "../../components/admin/common/Tab.vue";
import Countries from "../../components/admin/settings/Countries.vue";
import Languages from "../../components/admin/settings/Languages.vue";
</script>
CodePudding user response:
When using <script setup>
, the <component>.is
prop needs to be set to the component definition itself (not the component's name).
One solution is to track the active index (instead of active tab component):
Change
activeTab
to be a computed prop that returns the current tab fromtabs[]
based on the active index.Create an
activeIndex
ref, initialized to0
.In the
v-for
, include theindex
iteratorIn the
button
'sclick
handler, set theactiveIndex
to the currentindex
.In the
class
binding, compare the currentindex
toactiveIndex
.
<script setup>
import { onMounted, ref, computed } from 'vue'
const props = defineProps({
titles: {},
tabs: {},
})
1️⃣
const activeTab = computed(() => props.tabs[activeIndex.value])
2️⃣
const activeIndex = ref(0)
</script>
<template>
<div >
<button
3️⃣
v-for="(title, index) in titles"
4️⃣
@click="activeIndex = index"
v-text="title"
5️⃣
:
/>
</div>
<div >
<component :is="activeTab"></component>
</div>
</template>
Also, make sure to call markRaw()
on the component definitions in the binding to avoid the unnecessary overhead of reactivity. This also resolves a Vue warning about this in the browser console.
<template>