rodriciru
rodriciru

Reputation: 151

Vue how to customize global navbar at view level

Im super new to Vue. i have a Vue-CLI app, which have a navbar and content. Navbar is common to all pages, but i want to customize in each page whit some additional content.

Example:

Common-> home | about

View home -> home | about | your are in view home

View about -> home | about | your are in view about

router/index.js

import Vue from 'vue';
import VueRouter from 'vue-router';
import Home from '../views/Home.vue';
import NavBar from '@/components/NavBar.vue';
Vue.use(VueRouter);
Vue.component('nav-bar', NavBar);

//...

components/navbar.vue

 <template>
  <div>     
    <b-nav-item to="/">home</b-nav-item>
    <b-nav-item to="/about">about</b-nav-item>

    {{customContent}}
 </div>
</template>

<script>

export default {
  name: 'NavBar',
  props: {
    customContent: {
      type: String,
      default: 'default Content',
    },
  },
};
</script>

App.vue

<template>
<div id="app">
  <nav-bar />
  <div class="container-fluid">
    <router-view />
  </div>
</div>
</template>

views/home.vue

 <template>
  <div class="row">
    <div class="col-12">
        <image-card :images="images"/>
    </div>
  </div>
</template>
<script>
//how can i customize here the navbar by adding for example 'your are in view home'???
</script>

Thanks so much!

Upvotes: 1

Views: 7586

Answers (3)

LetsGoLlama
LetsGoLlama

Reputation: 1

You can access to router name like this:

 <div v-if="this.$route.name == 'home'">
        <HeaderTransparent />
 </div>
 <div v-else>
        <HeaderWhite />
 </div>

Upvotes: 0

TJ Weems
TJ Weems

Reputation: 1114

I use a breadcrumb to achieve a similar thing. Just an idea but Vue router allows you to add meta data to the current route which you always have access to

router.js

path: '/add',
name: 'add',
component: () => import(/* webpackChunkName: "add" */ '../../views/Add.vue'),
meta: {
    breadCrumb: [
        { name: 'Add New' }
    ]
},

Notice the meta object attached to the route.. this will be used to describe the current view.

Breadcrumb.vue component

<template>
  <div class="breadcrumb">
    <ul class="d-flex m-0 p-0"
      <li
        v-for="(breadcrumb, idx) in breadcrumbList"
        :key="idx">
        {{ breadcrumb.name }}
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  name: 'Breadcrumb',
  data () {
    return {
      breadcrumbList: []
    }
  },
  mounted () { this.updateList() },
  watch: { '$route' () { this.updateList() } },
  methods: {
    routeTo (pRouteTo) {
      if (this.breadcrumbList[pRouteTo].link) this.$router.push(this.breadcrumbList[pRouteTo].link)
    },
    updateList () { this.breadcrumbList = this.$route.meta.breadCrumb },
    formatPath(path) {
      const newPath = path.replace(/\//g, " > ")
      return newPath
    }
  }
}
</script>

And then you can import the breadcrumb into your navbar or where ever you would like to place it

<Breadcrumb class="breadcrumb" />

import Breadcrumb from '@/components/Breadcrumb.vue'

components: {Breadcrumb}

So basically the breadcrumb will always watch your current route and change the data based on the meta data you provide in your router.js file

Upvotes: 0

Guru Prasad
Guru Prasad

Reputation: 4223

There are a few ways in which you can solve this problem. I'll list two of them.

1. Update NavBar by $route

In this approach, the NavBar component already contains all of the possible combinations, and will display the relevant portion(s) depending on what $route contains.

Here's some pseudo code:

navbar.vue

<template>
<div class="navbar">
  <div class="navbar-left>
    APPNAME
  </div>
  <div v-if="name === 'landing'">
    ...
  </div>
  <div v-else-if="name === 'room'">
    ...
  </div>
</div>
</template>

App.vue

<template>
<div id="app">
  <NavBar :name="$route.name"/>
  <main>
    <router-view/>
  </main>
</div>
</template>

In this example, the NavBar component is very rigid, and doesn't really lend itself to much reuse. However, it does encapsulate all the relevant code relating to the nav bar.

2. Extensible NavBar with slots

In this approach, the NavBar only provides the bare-minimum to create a nav bar. The rest of the route-specific elements are to be filled in by the views.

navbar.vue

<template>
<div class="navbar">
  <div class="navbar-left">
    <div class="navbar-brand">
      APPNAME
    </div>
    <slot name="left"></slot>
  </div>
  <div class="navbar-right">
    <slot name="right"></slot>
  </div>
</div>
</template>

App.vue

<template>
<div id="app">
  <router-view/>
</div>
</template>

landing.vue

<template>
<div>
  <header>
    <NavBar>
      <template slot="right">
        <span>
          <div class="navbar-item">
            <div class="buttons">
              <button class="button" @click="...">Start Watching</button>
            </div>
          </div>
        </span>
      </template>
    </NavBar>
  </header>
  <main>
    ...
  </main>
</div>
</template>

This approach has a bit of repetition in terms of DOM elements, but gives you an extremely flexible NavBar that can be customized by each view.

The approach you want to use depends on what is important to you.
If strict encapsulation is what you want, then you may want to use approach 1, as all of the NavBar-related code is contained within a single file. However, if you believe that there is a potential for reuse, or if you would like all view-related code to live in one place, then it makes sense to use slots instead and extend the NavBar as required by each view.

Upvotes: 5

Related Questions