Skip to content

Layouts

David Graham edited this page Jun 26, 2018 · 3 revisions

Layouts are a great way to group page design or functionality in our app.

Changing Layouts

Our app.vue is responsible for swapping out layouts depending on which layout is being used by a route. The app will look in the Vuex store for this.$store.state.common.layout property and update the component reactively:

src/app.vue

<template lang="pug">
  #app
    component(:is="component")
      slot
</template>

<script>
import PublicLayout from '@/layouts/public/main.vue'
import DefaultLayout from '@/layouts/default/main.vue'

export default {
  name: 'App',

  components: {
    PublicLayout,
    DefaultLayout
  },

  computed: {
    component () {
      return this.$store.state.common.layout
    }
  },

  mounted () {
    // Update page title.
    this.$store.watch((state) => {
      return state.common.title
    }, (title) => {
      document.title = title
      console.log('title updated')
    }, {
      deep: true
    })
  }
}
</script>

A layout is associated with a route in the routes.js file:

src/http/routes.js

/**
 * Every route becomes a chunk, loaded only when used.
 * Reduces size of initial App load.
 */
const routes = [
  {
    name: 'login',
    path: '/login',
    component: () => import(/* webpackChunkName: "login" */ '@/features/login/main.vue'),
    title: 'Login',
    layout: 'PublicLayout',
    isPublic: true
  },
  {
    name: 'home',
    path: '/',
    component: () => import(/* webpackChunkName: "dashboard" */ '@/features/dashboard/main.vue'),
    title: 'Dashboard',
    layout: 'DefaultLayout',
    isPublic: false
  },

  // ...

]

export default routes

Functionality added to router.js will change the Vuex store common.layout property whenever a route is changed. Using a Vuex action store.dispatch('common/updateLayout', route.layout):

src/http/router.js

// ...

/**
 * The Router instance containing all the routes for the application.
 */
const router = new Router({
  base: '/app',
  mode: 'history',
  routes: routes.map(route => ({
    name: route.name,
    path: route.path,
    component: route.component,
    beforeEnter: (to, from, next) => {
      // Setup some per-page stuff.
      document.title = route.title
      store.dispatch('common/updateTitle', route.title)
      store.dispatch('common/updateLayout', route.layout)

      // Auth navigation guard.
      if (!route.isPublic) return guardRoute(to, from, next)

      next()
    }
  }))
})

// ...

Default

As an example, we have a default layout that we will use for most of our authenticated pages. The layout consists of a top app-toolbar, side-navigation drawer, footer, an app dialog and snackbar (for features in our app to use for basic messages if they so prefer):

src/layouts/default/main.vue

<template lang="pug">
  v-app.my-default-layout
    app-sidebar
    app-bar
    v-content(style="padding-top: 48px;")
      transition(name="slide" mode="out-in")
        router-view
    app-footer
    app-dialog
    app-snackbar
</template>

<script>
import AppBar from '@/components/app-bar'
import AppSidebar from '@/components/app-sidebar'
import AppDialog from '@/components/app-dialog'
import AppSnackbar from '@/components/app-snackbar'
import AppFooter from '@/components/app-footer'

export default {
  name: 'DefaultLayout',

  components: { AppBar, AppSidebar, AppDialog, AppSnackbar, AppFooter },

  methods: {

  }
}
</script>

<style lang="stylus">
</style>

Public

To demonstrate the swapping of one layout to another, we have a different layout we can use for an unauthenticated, public login page:

src/layouts/public/main.vue

<template lang="pug">
  v-app
    transition(name="slide" mode="out-in")
      router-view
</template>

<script>
export default {
  name: 'PublicLayout'
}
</script>

<style lang="stylus">

</style>

Clone this wiki locally