Within my Vue application, I have a page that contains various tabs. My goal is to display different tabs based on the routes being accessed.
To achieve this functionality, I followed an answer provided in this link.
Overall, it's working well! I can even switch tabs by swiping on mobile devices, thanks to the @change
listener attached to the v-tabs-items
.
However, when I click on the tab labels, the component loaded via the <router-view>
seems to be mounted twice. On the contrary, when swiping, it's only mounted once.
This issue seems to stem from the fact that the <router-view>
is nested within the loop of <v-tab-item>
s.
If I move it outside of this loop, the child components are properly mounted just once. Unfortunately, this means sacrificing the swipe feature because the content becomes detached.
So: Is there a way to preserve both functionalities (dynamically routed content and swipability)?
Thank you!
Vue:
<template>
<!-- [...] -->
<v-tabs centered="centered" grow v-model="activeTab">
<v-tab v-for="tab of tabs" :key="tab.id" :id="tab.id" :to="tab.route" exact>
<v-icon>{{ tab.icon }}</v-icon>
</v-tab>
<v-tabs-items v-model="activeTab" @change="updateRouter($event)">
<v-tab-item v-for="tab of tabs" :key="tab.id" :value="resolvePath(tab.route)" class="tab_content">
<!-- prevent loading multiple route-view instances -->
<router-view v-if="tab.route === activeTab" />
</v-tab-item>
</v-tabs-items>
</v-tabs>
<!-- [...] -->
</template>
<script lang="ts">
data: () => ({
activeTab: '',
tabs: [
{id: 'profile', icon: 'mdi-account', route: '/social/profile'},
{id: 'friends', icon: 'mdi-account-group', route: '/social/friends'},
{id: 'settings', icon: 'mdi-cogs', route: '/social/settings'},
]
}),
methods: {
updateRouter(tab:string) {
this.$router.push(tab)
}
},
</script>
Router:
{
path: "/social",
component: () => import("../views/Social.vue"),
meta: {
requiresAuth: true
},
children: [
{
path: "profile",
component: () => import("@/components/social/Profile.vue")
},
{
path: "friends",
component: () => import("@/components/social/Friendlist.vue")
},
{
path: "settings",
component: () => import("@/components/social/ProfileSettings.vue")
}
]
}