Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

vue.js structure application layout

Tags:

vue.js

I wish to build my web application with the Holy Grail layout, with just one sidebar, and no footer. The sidebar will be used as a navigation bar, as well as for holding interactive option for content that will be displayed in the center of the layout, depending on the currently chose link. Meaning that, when choosing a link to navigate to in the navigation bar, it will affect the displayed content in the sidebar for custom interaction options, and the main content in the center.

For achieving this I have came up with couple of approaches:

  1. Approach 1:
    • Have one Vue instance
    • Have a Layout component creating our layout, with Header and Navbar for sub-components.
    • Our Vue instance will use a router with a path for each link present in the navigation sidebar
    • Our Vue instance will render one router-view component to display the current path component
    • Each route will display a component that its template is using our previously created Layout component and inject the appropriate custom navigation options, and main content using slots.

Layout component:

<template>
<div class="app-layout">
    <header-component></header-component>
    <div class="main">
      <navbar-component>
        <slot name="navigation-menu"></slot>
      </navbar-component>
      <main>
        <slot name="main-content"></slot>
      </main>
    </div>
  </div>
</template>

<script>
  import Header from './Header.vue';
  import Navbar from './Navbar.vue';
  export default {
    name: 'Layout',
    components: {
      'header-component': Header,
      'navbar-component': Navbar
    }
  };
</script>

<style lang="sass" rel="stylesheet/scss" scoped>
  some styling to achieve our layout for the present tags in the template
</style>

Header component:

<template>
  <header v-once class="header">
    <router-link to="/">
      Brand
    </router-link>
  </header>
</template>

<script>
  export default {
    name: 'Header'
  };
</script>

<style lang="sass" rel="stylesheet/scss" scoped>
  some styling to achieve our layout for the present tags in the template
</style>

Navbar component:

<template>
  <nav class="navigation">
    <div class="links">
      // iterate on some property of this component, and create a list of links
    </div>
    <div class="menu">
      <slot name="navigation-menu"></slot>
    </div>
  </nav>
</template>

<script>
  export default {
    name: 'Navbar'
  };
</script>

<style lang="sass" rel="stylesheet/scss" scoped>
  some styling to achieve our layout for the present tags in the template
</style>

Vue instance with routing:

import link1Component from './components/Link1ComponentUsingLayout.vue';
import link2Component from './components/Link2ComponentUsingLayout.vue';
import link3Component from './components/Link3ComponentUsingLayout.vue';

const router = new VueRouter({
  mode: 'history',
  routes: [
    {
      path: '/',
      redirect: '/link1'
    },
    {
      path: '/link1',
      name: 'link1',
      component: Link1ComponentUsingLayout
    },
    {
      path: '/link2',
      name: 'link2',
      component: Link2ComponentUsingLayout
    },
    {
      path: '/link3',
      name: 'link3',
      component: Link3ComponentUsingLayout
    }
  ]
});

export default new Vue({
  el: '#app',
  router,
  render: h => h('router-view')
});
  1. Approach 2:
    • Have two Vue instances
    • Have out layout as a static html inside index.html instead of a component
    • Each of the Vue instances will use a router (one for each), with a path for each link present in the navigation bar
    • One of the instances will be mounted on the html inside the navigation sidebar in our static html, and one inside the center content area
    • Each of the Vue instances will render one router-view component to display the current path component
  2. Approach 3:
    • Have one Vue instance
    • Our Vue instance will use a router with a path for each link present in the navigation sidebar
    • Or Vue instance will template will represent our layout and inside the navigation sidebar, and the center content area we'll have 2 router-view components
    • Our Vue instances will render both the navigation sidebar, and the center content are components for the current path
  3. Approach 4:
    • Same as Approach 3, except don't use router and use dynamic components to switch between the navigation sidebar, and the center content area components, whenever a link inside the navigation is clicked.

Now, I was wondering which approach would be the best and why? Also I would like to hear new approaches if you have any, and explanation for why they're better.

like image 445
Jorayen Avatar asked Oct 12 '16 23:10

Jorayen


1 Answers

I don't have an explanation if this would be better, but I would like to add another approach I've previously used.

Assume that your project needs multiple layouts such as a layout for the admin, a separate one for the end user, and so on. Although this doesn't seem to really fit your use case, you could consider it an addition.

Layout.vue

Your Layout will contain the components that will persist on any page under it.

<template>
  <div>
    <header-component />

    <div class="main">
      <navbar-component />

      <main>
        <!-- your child routes here -->
        <router-view />
      </main>
    </div>
  </div>
</template>

router.js

In your routes, you nest your components or views under Layout.vue like so:

routes: [
  {
    path: '',
    component: Layout,
    // child routes now have the style of Layout
    children: [
      {
        path: '/page1',
        name: 'Page1Name',
        component: Page1
      },
      // ...
    ]
  }
]

Child components of Layout.vue are shown in its <router-view />.

NavComponent.vue

<template>
  <nav class="navigation">
    <!-- links and other stuff -->

    <!-- your custom interactive options below -->

    <div v-if="isInRoutes('Page1Name')">
      <!-- div or some component for Page1 -->
    </div>
  </nav>
</template>

wherein isInRoutes method checks for this.$route.name or it can be more complex than that.

Your App.vue (the one you'll render with h(App)) will also contain a <router-view /> of its own so it will show the layouts.

App.vue

<template>
  <div>
    <router-view />
  </div>
</template>

With this approach, you can create multiple layouts and nest your components under a particular layout using your routes.

like image 101
Arnesfield Avatar answered Oct 07 '22 01:10

Arnesfield