moody1208
moody1208

Reputation: 559

Toggle nav animation in Nuxt

I have a simple animation using GSAP being applied when toggling navigation into view. I am building this site in Nuxt/Vue (which is new to me) so I think the problem might be how I've structured my functions.

My nav toggle button and nav layout are in two separate components so I've used Vuex to pass data between them to add/remove the active state. The logic/animation works fine for pages to load, clicking the toggle to activate the nav and seeing the loading in animation. The problem is for animating the menu out when closing. For some reason I keep getting Cannot read property 'querySelectorAll' of undefined, which I think is due to Nuxt SSR running on page load and trying to run the animateNavOut function (when it shouldn't).

As I mentioned, Vue/Nuxt is new for me so any suggestions to make this code work/a better way o doing this would be appreciated.

Nav Component

<template>
  <transition name="card">
    <div class="nav" :class="toggleNav()">
      <div class="nav__panel">
        <div class="nav__panel-inner">
          <div class="nav__panel-contact">
            <div class="h-3">Contact Us</div>
            <ul>
              <li>
                <a href="tel:07498-916-341">+44(0)7498 916 341</a>
              </li>
            </ul>
            <div class="nav__panel-social">
              <SocialLinks />
            </div>
          </div>
        </div>
      </div>
      <div class="nav__panel">
        <div class="nav__panel-inner">
          <nav class="nav__panel-nav">
            <ul>
              <li>
                <NuxtLink to="/">Home</NuxtLink>
              </li>
              <li>
                <NuxtLink to="/about-us">About Us</NuxtLink>
              </li>
              <li>
                <NuxtLink to="/our-expertise">Our Expertise</NuxtLink>
              </li>
              <li>
                <NuxtLink to="/contact-us">Contact Us</NuxtLink>
              </li>
            </ul>
          </nav>
        </div>
      </div>
    </div>
  </transition>
</template>

<script>
import { gsap } from 'gsap'

export default {
  data() {
    return {
      isActive: 'is-active',
    }
  },

  methods: {
    toggleNav() {
      if (this.$store.state.navIsActive === true) {
        this.animateNavIn()
        return this.isActive
      } else {
        this.animateNavOut()
      }
    },

    animateNavIn() {
      console.log('animate in')

      const TL = gsap.timeline()

      TL.to('.nav__panel-nav ul li a', {
        duration: 1,
        autoAlpha: 1,
        y: 0,
        stagger: 0.05,
        ease: 'Power2.out',
      }).to(
        '.nav__panel-contact .h-3, li, .social__title, .social__links',
        {
          duration: 1,
          autoAlpha: 1,
          y: 0,
          stagger: 0.05,
          ease: 'Power2.out',
        },
        '-=.9',
      )
    },

    animateNavOut() {
      console.log('animate out')

      const TL = gsap.timeline()

      TL.to('.nav__panel-nav ul li a', {
        duration: 1,
        autoAlpha: 0,
        y: '15px',
        stagger: 0.05,
        ease: 'Power2.out',
      })
    },
  },
}
</script>

Nav toggle

<template>
  <button class="nav-toggle" :class="{ 'is-active': isActive }" @click="navToggle()">
    <span></span>
  </button>
</template>

<script>
export default {
  data() {
    return {
      isActive: false,
    }
  },

  computed: {
    // Return default/current value for nav status from VUEX using Getter
    navState() {
      return this.$store.getters.navState
    },
  },

  methods: {
    navToggle() {
      // Set toggle active state
      this.isActive = !this.isActive

      // Update nav status by passing state back into VUEX using mutations
      if (this.$store.state.navIsActive === false) {
        this.$store.commit('setNavState', true)
        document.getElementsByTagName('body')[0].classList.add('no-scroll')
      } else {
        this.$store.commit('setNavState', false)
        document.getElementsByTagName('body')[0].classList.remove('no-scroll')
      }
    },
  },
}
</script>

Vuex store

export const state = () => ({
  navIsActive: false
});

export const getters = {
   // Retrieve info from Store or use computed property, but a getter can be used everywhere
   navState(state) {
    return state.navIsActive;
  }
}

export const mutations = {
  // Update nav status based on payload passed in via method function in component
  setNavState(state, payload) {
    state.navIsActive = payload;
  }
}

Upvotes: 0

Views: 1033

Answers (1)

kissu
kissu

Reputation: 46814

I never tried to import the vanilla GSAP package but the Nuxt one is working great and simple to install: nuxt-gsap-module

You do have an error with querySelectorAll, the thing is that you should not use this kind of selector into an SPA like VueJS. You should rather use $refs as shown in the documentation, like this

<base-input ref="usernameInput"></base-input>

<script>
  // ...
  this.$refs.usernameInput
</script>

Give a read to this page where you can see some VueJS examples on how to animate with GSAP: https://v2.vuejs.org/v2/cookbook/editable-svg-icons.html#Animatable-Icons

Upvotes: 1

Related Questions