Here are 3 options:
1. Simple Computed View
To allow a single route to display any number of conditional views, use a computed component.
Register views:
import Vue from 'vue'
import ViewDefault from '/views/Default.vue'
Vue.component('view-default', ViewDefault )
import ViewAuth from '/views/Auth.vue'
Vue.component('view-auth', ViewAuth )
import ViewGuest from '/views/Guest.vue'
Vue.component('view-guest', ViewGuest)
Route:
{
path: '/',
name: 'index',
component: ViewDefault
},
View Default.vue
<template>
<component :is="view"></component>
</template>
<script>
export default {
name: 'view-default',
computed: {
view() {
return this.isAuthenticated ? 'view-auth' : 'view-guest'
}
}
}
</script>
You will be able to create as many conditional checks you want in view().
2. Conditional Named Views ( Concept not tried )
I would consider experimenting with the use of named views, I believe you could double view many paths with user and guest versions, not something I tried yet:
https://router.vuejs.org/guide/essentials/named-views.html
<template>
<div>
<template v-if="isAuthenticated">
<router-view name="authed"/>
</template>
<template v-else>
<router-view/>
</template>
</div>
</template>
Router
const router = new VueRouter({
routes: [
{
path: '/',
components: {
default: MainGuest,
authed: MainAuth,
}
}
]
})
3. Computed Layouts
However ... I personally use I/O blocking layouts, computed layout.
I check various application states that control what layouts are displayed depending on the conditions before a final layout is computed that would contain <router-view>.
I let the router paths specify custom layouts via meta data, set alternate layout else falls back to default layout.
Router
{
name: 'index',
path: '/',
meta: {
title: 'Welcome',
guard: 'auth'
},
component: import('@/views/welcome')
},
{
name: 'settings',
path: '/settings',
meta: {
title: 'Account Settings',
layout: 'settings',
guard: 'auth'
},
component: import('@/views/account-settings')
}
App.vue
<template>
<div id="app" v-cloak :class="$root.layout">
<transition name="component-fade" mode="out-in">
<component :is="$root.layout"/>
</transition>
</div>
</template>
main.js
import Vue from 'vue'
import router from './router'
import store from './store'
import '@/views/layouts'
import App from './App'
// Use Vuex to store states, `axios` calls and response `interceptors` are used to `commit` computed mapped state conditions globally.
import { mapState, mapGetters } from 'vuex'
Vue.mixin({
computed: {
...mapState(['user', 'isAuthenticating', 'isOffline']),
...mapGetters(['isAuthenticated']),
}
})
new Vue({
el: '#app'
render: h => h(App),
store,
router,
computed: {
layout () { // could move this to vuex and access via mapGetters...
if (this.isOffline) {
return 'layout-offline'
}
if (this.isAuthenticating) {
return 'layout-authenticating'
}
if (this.$route.meta.hasOwnProperty('guard')) {
if(this.$route.meta.guard === 'auth' && !this.isAuthenticated) {
return 'layout-login'
}
}
// If current route has a preferred layout use it else fallback to `layout-default`
let layout = this.$route.meta.layout || 'default'
return `layout-${layout}`
}
},
})
views/layouts/index.js
import Vue from 'vue'
import LayoutOffline from './layout-offline')
import LayoutAuthenticating from './layout-authenticating')
import LayoutLogin from './layout-login')
import LayoutDefault from './layout-default')
import LayoutSettings from './layout-settings')
Vue.component('layout-offline', LayoutOffline)
Vue.component('layout-authenticating', LayoutAuthenticating)
Vue.component('layout-login', LayoutLogin)
Vue.component('layout-default', LayoutDefault)
Vue.component('layout-settings', Layoutsettings)
Only layout-default or any router path specifying a custom layout should contain <router-view> along with header, footer, sidebar etc...
You could mix this up with name views, different computed layouts could display a different named router-view for the same path.