Reputation: 1971
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:
Layout
component creating our layout, with Header
and Navbar
for sub-components.router-view
component to display the current path componentLayout
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')
});
router-view
component to display the current path componentrouter-view
componentsNow, 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.
Upvotes: 13
Views: 5858
Reputation: 508
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 forthis.$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.
Upvotes: 1
Reputation: 91
I think you can refer to the more mature code.
I think the approach in this project is very similar to your idea.
Upvotes: 0
Reputation: 1393
The first approach is probably the best way except you don't have a router-view
anywhere. You also don't need to use slots unless your navigation will be changing. And if your navigation is changing you probably would do this logic inside the Navbar
component anyways.
You can simplify your Layout
component to this:
<template>
<div class="app-layout">
<header-component />
<div class="main">
<navbar-component />
<main>
<router-view />
</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>
The way you are calling h => h('router-view')
is going to render the entire app as a router-view
which is not what you want. You will only want the main
div to be changing content based on the route you are in. Change this to:
export default new Vue({
el: '#app',
router,
render: h => h(require('./Layout')) //change this path to where Layout.vue is
});
Which will make your Layout
component the root component of your app.
Upvotes: 0
Reputation: 4697
As much as possible, dont structure your code around your layout. That's the takeaway I would hope for you.
I tend to use basically 2 but one level deep (like 3). I have an app component to load vue stuff from components
folder. There I have a router-view
in main to show the route, a header component for header and navbar, and a modals component at the bottom of main.
Upvotes: 0