I’m just learning Vue and trying to learn dynamic rendering using the component tag. What is the problem with this code? No errors are displayed in the console, but clicking on the buttons still does not display the required component. It does work with v-if, but the point of this lecture I’m following is to use the component dynamic rendering. Which does not work:
<template>
<div>
<the-header></the-header>
<button @click="setSelectedComponent('active-goals')">Active goals</button>
<button @click="setSelectedComponent('manage-goals')">Manage goals</button>
<component :is="selectedTab"></component>
</div>
</template>
<script setup>
/* eslint-disable no-unused-vars */
import { ref, defineExpose, defineComponent } from 'vue';
import TheHeader from './components/TheHeader.vue';
import ActiveGoals from './components/ActiveGoals.vue';
import ManageGoals from './components/ManageGoals.vue';
const selectedTab = ref('active-goals');
const setSelectedComponent = (tab) => {
selectedTab.value = tab;
};
defineExpose({
selectedTab,
setSelectedComponent,
});
defineComponent({
components: {
TheHeader,
ActiveGoals,
ManageGoals,
},
});
</script>
<style>
html {
font-family: sans-serif;
}
body {
margin: 0;
}
</style>
Thanks for any help!
4
Answers
In script setup the imported components are treated as variables because they’re not registered under keys as we do in
components
option in non script setup syntax, so you can map them with keys inside an object :UPDATE 2
Playground with the tao’s solution
UPDATE
Answering the question from tao:
To make
<component :is="">
work with strings, you have to register you components with names.You don’t need
defineComponent
in this case.Check the original Vue Solution for Tabs in the
Dynamic Components
Working Playground with your code
Here is you fixed code:
for this to work you can register your components globally, for Vue to make the link with your selected component. Otherwise, you can use the defineAsync method from Vue.
registerGlobally
defineAsync
1:
your .vue
In your main
2:
your .vue
You can’t use strings with
:is
if the components are not registered.You either use the components themselves instead of the strings (@Tolbxela’s or @Bussadjra’s answers), or register the components.
And you can’t register the components (easily) in
<script setup>
, because<script setup>
syntax is limited. It’s literally a macro to write:as:
… with some mods to allow
import
s inside thesetup()
function and few more other goodies (defineProps
,defineEmits
, etc…).The limitation should be obvious: if you need anything besides the contents of
setup()
function fromdefineComponent()
, you want to use a normal<script>
.In other words,
<script setup>
should be treated as a tool to reduce boilerplate, you shouldn’t put effort into attempting to write all your components using it.Last, but not least,
<script setup>
can be used alongside a normal<script>
tag. In your case:The normal
<script>
registers the components so<template>
can translate the strings into actual components.