Reputation: 1317
So the vast majority of views on my vuejs SPA have a navbar component at the top. However, some select views such as the login should not display this.
My workaround was to import the navbar and add to each view individually if it was needed, but now I can see it causes a weird flickering when going from one view to another - presumably because the navbar component is being removed, and immediately re-added. This seems wrong.
I assume there's some way to add the navbar component in App.vue but conditionally hide it on some routes with vue-router? What's the best practice for this?
Upvotes: 13
Views: 23159
Reputation: 343
I know it's old, but I use a different way.
Just watch the route name change. I like to to use auth.login
or auth.register
for my routes.
<v-app-bar v-if="!currentRouteName.startsWith('auth')"></v-app-bar>
And then:
data() {
return{
currentRouteName: 'home',
}
},
watch:{
['$route.name'](route) {
this.currentRouteName = route
}
}
Upvotes: 0
Reputation: 11
in router-> index.js write child routes and in parent - whatever global component is there write at that point, and at children write where we want to show
const router = new VueRouter({
mode: "history",
base: process.env.BASE_URL,
routes: [
{ path: "/", redirect: "/login" },
{ path: "/registration", component: registration },
{
path: "/home",
component: navbar,
children: [
{
path: "/home",
name: "home",
component: () => import("../views/Home.vue"),
},
{
path: "/notes",
name: "notes",
component: () => import("../views/notes/Index.vue"),
},
{
path: "/notes/create",
name: "notescreate",
component: () => import("../views/notes/Create.vue"),
},
{
path: "/notes/edit/:id",
name: "notesedit",
component: () => import("../views/notes/Edit.vue"),
},
{ path: "/myposts", component: myPosts },
{ path: "/allposts", component: allPosts },
{ path: "/create", component: create },
{ path: "/edit/:id", component: edit },
],
},
{
path: "/login",
name: "login",
component: () => import("../views/Login.vue"),
},
],
});
dont forget to write in app.vue
without router-view - it will not going to work
Upvotes: 0
Reputation: 506
Route Meta Fields solved this problem for me:
//router.js
{
path: '/login',
name: 'login',
component: () => import(/* webpackChunkName: 'login' */ '@/components/Login.vue'),
meta: {
hideNavbar: true,
}
}
//App.vue
<Navbar v-if="!$route.meta.hideNavbar" />
Upvotes: 23
Reputation: 1968
A common way is to use nested routes. Here is an example from one of my projects:
const router = new Router({
mode: 'history',
base: process.env.BASE_URL,
routes: [
{
path: '/login',
name: 'login',
component: LoginView,
},
{
path: '/admin',
name: 'admin',
component: AdminShell,
children: [
{
path: 'home',
name: 'admin_home',
component: AdminHomeView
},
]
},
],
});
The main view will just have a router-view component, so the login view component can be displayed without the navbar.
<!-- App -->
<v-app>
<v-content>
<router-view> </router-view>
</v-content>
</v-app>
The admin shell will be injected into the main view, and it will contain the navbar, side bar and what ever else it needs.
<!-- Admin shell -->
<v-container fill-height>
<v-toolbar color="blue darken-3" dark app :clipped-left="$vuetify.breakpoint.mdAndUp" fixed>
<v-toolbar-title style="width: 300px" class="ml-0 pl-3">
<v-toolbar-side-icon @click.stop="drawer = !drawer"></v-toolbar-side-icon>
<span class="hidden-sm-and-down">Admin</span>
</v-toolbar-title>
<v-spacer></v-spacer>
<UserInfo></UserInfo>
</v-toolbar>
<!-- Nested route -->
<router-view></router-view>
</v-container>
Then, the AdminHomeView will be injected into nested router-view of the admin shell view.
Upvotes: 17
Reputation: 306
We can conditionally render components by checking the name of the current route using v-if directive. I used this in a recent project.
My route index.js file
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
import Login from '../views/Login.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'home',
component: Home
},
{
path: '/login',
name: 'login',
component: Login
},
{
path: '/register',
name: 'register',
component: Register
}
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
export default router
My App.vue file
<template>
<div id="app">
/* Note that this takes an array of route names, so you can simply pass in
the name of the route you don't want this component to be displayed on */
<navbar v-if="!['login', 'register', 'help'].includes($route.name)" />
<main>
<router-view />
</main>
<appfooter v-if="!['login', 'register'].includes($route.name)"/>
</div>
</template>
Upvotes: 8
Reputation: 7150
I prefer a conditionally rendered component in the main view over @Edins nested routes approach.
Vue provides a great global state store via Vuex
which makes this incredibly simple as well.
The classic example would be to only have the navbar when the user is logged in.
So you track the login status in the state store, then use a computed getter in your main view (or App.vue):
<template>
<navbar v-if="isAuthenticated"/>
<router-view/>
</template>
export default {
name: 'App',
computed: {
isAuthenticated() {
return this.$store.getters.isAuthenticated
},
},
Upvotes: 10