Darrell Brogdon
Darrell Brogdon

Reputation: 6973

Conditional state based on the route

I have a Vuex state property that stores a boolean that I use to determine whether to show or hide the nav bar. For all pages except the landing page the nav bar should appear so I set the default value to true.

export const state = () => ({
    showNav: true
})

Then I have a mutation for toggling that.

export const mutations = {
    toggleNav (state, show) {
        state.showNav = show
    }
}

In my landing page, I have a call to toggleNav to turn off the nav bar.

export default {
    mounted () {
        this.$store.commit('toggleNav', false)
    }
}

This works as expected with one big problem; When I refresh the landing page I see the nav bar for a brief second until mounted() gets called.

Is there some way to hide the nav bar such that it doesn't briefly appear? I realized I could default showNav to false and then call this.$store.commit('toggleNav', true) on every page but that seems unwieldy.

EDIT: The nav bar is itself its own component.

EDIT 2: I forgot to add that I need to be able to dynamically show the nav bar when scrollY exceeds a certain value and then hide it again when scrollY returns below that value. My apologies to everyone who answered for not being clearer about this.

Upvotes: 3

Views: 1258

Answers (2)

yqlim
yqlim

Reputation: 7080

In Nuxt, middlewares attached to a layout or a page are run on load and on every route change.

So the most straightforward way is to use a middleware to check for current path and toggle your nav:

/* store/index.js */
export const store = () => ({
  showNav: true
});

export const mutations = {
  toggleNav(state, bool){
    state.showNav = bool;
  }
}


/* middleware/toggleNavMiddleware.js */
export default function(context){
  const { route, store } = context;
  store.commit('toggleNav', route.path === /* your landing page path */);
}


/* layouts/default.vue (assuming this is the target) */
/* you can also use it in pages/*.vue */
export default {
  middleware: ['toggleNavMiddleware'],
}


/* components/NavBar.vue */
<template>
  <nav v-if="$store.state.showNav">
    <!-- content here -->
  </nav>
</template>

Upvotes: 1

Yom T.
Yom T.

Reputation: 9180

Rather than relying on state mutation, this had probably best be done during design-time by including a meta field when defining the routes. Something like meta.showNavBar. For example:

routes.js

export default [
  {
    // The landing page
    path: '/welcome',
    name: 'Welcome',
    meta: {
      showNavbar: false
    },
    component: () => import('@/views/Welcome')
  },

  {
    path: '/',
    name: 'Homepage',
    meta: {
      // Don't worry about this since we'll take care of it with a computed property.
      // showNavbar: true
    },
    component: () => import('@/views/Home')
  },

  {
    // ...
  }
]

SomeComponent.vue

<template>
  <navbar v-if="showNavbar"></navbar>
</template>

<script>
  export default {
    computed: {
      showNavbar() {
        const { showNavbar } = this.$route.meta;

        return showNavbar || typeof showNavbar === 'undefined';
      }
    }
  }
</script>

Alternatively, you could call it meta.hideNavbar, set it to true for the landing page and coerce its value to boolean with double-negation operator (!!) -- which will default to false when not set or left undefined, from here, you could simply do:

<navbar v-if="!!$route.meta.hideNavbar"></navbar>

Upvotes: 0

Related Questions