As I've wrote in the title, I'm trying to build my own Tabs components. So far it's very basic:
Tabs.vue
setup(props, { slots }) {
const { activeTab } = toRefs(props);
provide("activeTab", activeTab);
const newSlots = slots.default().map((slot, index) => {
return h(slot, {
index, // for each tab to know, whether is active
key: index, // for TransitionGroup
});
});
return () =>
h(
TransitionGroup,
{
name: "tabs-fade",
},
() => newSlots
);
}
Tab.vue
<template>
<div v-if="activeTab === index">
<slot />
</div>
</template>
setup() {
const activeTab = inject("activeTab");
return {
activeTab,
};
},
And I've planned to use it like that:
Testing.vue
<ul>
<li @click="activeTab = 0">1</li>
<li @click="activeTab = 1">2</li>
<li @click="activeTab = 2">3</li>
</ul>
<Tabs :activeTab="activeTab">
<Tab> 1 </Tab>
<Tab> 2 </Tab>
<Tab> 3 </Tab>
</Tabs>
Without TransitionGroup everything works fine, although when I'm trying to add it for smoother transitioning, I'm getting an error when trying to switch between the tabs:
[Vue warn]: Unhandled error during execution of render function
at <TransitionGroup name="tabs-fade" >
at <Tabs activeTab=1 >
at <Testing>
at <App>
[Vue warn]: Unhandled error during execution of scheduler flush. This is likely a Vue internals bug. Please open an issue at https://new-issue.vuejs.org/?repo=vuejs/core
at <TransitionGroup name="tabs-fade" >
at <Tabs activeTab=1 >
at <Testing>
at <App>
Uncaught (in promise) TypeError: child.el.getBoundingClientRect is not a function
CodePudding user response:
TransitionGroup
expects a consistent number of children so that it can transition from one state to another. Currently, Tabs.vue
's root element is conditionally rendered, such that it's possible for there to be no element at all when the condition is not met, leading to the crash:
<!-- Tab.vue -->
<template>
<div v-if="activeTab === index"> ❌ when false, no element exists
<slot/>
</div>
</template>
Solution
Add a v-else
on a div
to ensure an element always exists in Tab.vue
:
<!-- Tab.vue -->
<template>
<div v-if="activeTab === index">
<slot/>
</div>
<div v-else />