Nuxt/Vue reactive body attributes

Viewed 14142

I want to add the class menu-opened on the body tag when I click on the menu burger div.

My div

<div v-on:click="openMenu"></div>

The openMenu method

methods: {
     openMenu() {
       console.log('open menu launch')
       this.$store.dispatch('menu/setMenu', true)
     }
    }

My store

state = {
    isMenuOpen: false
}

actions = {
    setMenu({ commit }, value) {
      commit('SET_MENU_OPEN_STATUS', value)
    }
}

mutations= {
    SET_MENU_OPEN_STATUS(state, newState){
        state.isMenuOpen = newState
    }
}

On my template, i got this code to add the class on the body based on the state of the isMenuOpen value :

export default {
    data() {
        return {
           menuState: this.$store.state.isMenuOpen
        }
    },
    head () {
      return {
        bodyAttrs: {
          class: this.menuState ? 'menu-opened' : ''
        }
      }
    }
}

My store is working well, the value change when I click on my div, but it's not adding the class, like if the head function is not reactive...

Thanks for your help

2 Answers

In Nuxt

This is because the head method is only called once on initial page load. If you would like to update the values you can, but you will need to call the head() function again.

You could do this with a watcher or you could call it from your store.

A quick and kind of dirty way would be with a combination of computed properties and a watcher..

export default {
    data() {
        return {
           menuState: this.$store.state.isMenuOpen
        }
    },
    head () {
      return {
        bodyAttrs: {
          class: this.isMenuOpen ? 'menu-opened' : ''
        }
      }
    },
   computed: {
     isMenuOpen () {
       return this.$store.state.isMenuOpen
     }
   },
   watch: {
     isMenuOpen () {
       this.head()
     }
   }
}

In Vue

You need to watch on events like mounted or beforeDestroy described there

https://v2.vuejs.org/v2/guide/instance.html

and use pure js to modify dom like

const bodyElement = document.querySelector('body')
bodyElement.classList.add('a');
bodyElement.classList.remove('b');
bodyElement.classList.toggle('c');

https://developer.mozilla.org/pl/docs/Web/API/Element/classList

You could do something like this:

My div

<div v-on:click="openMenu" ref="myDiv"></div>

The openMenu method

methods: {
     openMenu() {
       console.log('open menu launch')
       this.$refs.myDiv.closest('body').classList.add("menu-opened")
     }
    }

And then you need to implement similar functionality for the close-menu button, only using:

this.$refs.myDiv.closest('body').classList.remove("menu-opened")
Related