Jump to content
GreenSock

BenjaminO

Refresh Gsap animation breaks Nuxt 3

Recommended Posts

Hello 👋,

 

I created a mouse follower which scale up when hovering an anchor, button, input, textarea, label or select on a nuxt 3 project. The method I used is the following :

  function ScaleMouse(Items) {
    Items.forEach((link) => {
      // On mouse enter scale the media-cursor to 2
      link.addEventListener('pointerenter', () => {
        gsap.to(Cursor, {
          scale: 2,
          duration: 1,
          ease: 'power4.out',
        });
      });
      // On mouse leave scale the media-cursor to 1
      link.addEventListener('pointerleave', () => {
        gsap.to(Cursor, {
          scale: 1,
          duration: 1,
          ease: 'power4.out',
        });
      });
    });
  }

In order to refresh my list of elements (between pages), I am using a state management tool (Pinia) . I am defining a state to 0 which I increment from 1 when changing the page 

import { defineStore } from 'pinia';

export const routeStore = defineStore({
  id: 'page-store',
  state: () => {
    return {
      isNewPage: 0,
    };
  },
});

With the $subscribe method I can detect when the state is changed and thus resetting my variable Items

  isRoute.$subscribe(() => {
    Items = document.querySelectorAll(
      'a, button, input, textarea, label, select'
    );
    ScaleMouse(Items);
  });

 

My problem is that the ease effect (power4.out) I applied on scale is broken little by little when changing the page. This problem only affects fixed elements (containing buttons and anchors) that are in my app.vue file.

 

I created a reproduction on StackBlitz : https://stackblitz.com/edit/nuxt-starter-ugbwzw?file=app.vue

Steps to reproduce:

  • Hover the fixed button and the dynamic link
  • Navigate between pages without doing hard refresh
  • Hover again and notice the difference between the fixed button and the link

 

My question is : Is there another method to avoid this problem or is it a GSAP bug ? Thank you very much in advance for your responses ! 🙏 

Link to comment
Share on other sites

No, it's not a GSAP bug - it's a problem with your code: you keep adding more and more event listeners to the same element each time you navigate. So for example, if you go to 3 pages and then you roll over the "Fixed button", it will call 3 event handlers, firing 3 identical animations that are all fighting for control of the same properties of the same element. 

 

The best way to solve this is for you to not add a bunch of the same event handlers. Make sure you removeEventListener() when you leave the page, or add conditional logic to not add a new event handler when there's already one added. Alternatively, you could set overwrite: true or overwrite: "auto" on the tween(s) but even though that'd technically prevent conflicts, it's just masking the fundamental problem in your code. It's bad for performance to just keep stacking up more and more event handlers like that. If your user visits 30 pages, you really don't want a rollover to fire of 30 different handlers, creating 30 new animations and overwriting 29 of them. 

 

Does that clear things up? 

Link to comment
Share on other sites

hello @GreenSock and thank you for your response ! That was my thought indeed but I am not sure how to add some conditional logic in order to prevent a new event handler 🧐 Is there an handy/easy way to conditionally defined elements triggered by gsap animation ? otherwise what could be the best way to target all animations related to an element in order to remove them -> maybe with animation.kill(Cursor, "scale") ? 

Link to comment
Share on other sites

49 minutes ago, BenjaminO said:

That was my thought indeed but I am not sure how to add some conditional logic in order to prevent a new event handler 🧐

That has to do with the plumbing in your app - we really try to stay focused on GSAP-specific things here. But the general idea is to only add those even handlers once. Or if you're gonna add them multiple times, make sure you remove the old one before adding the new one each time (so there's always only one). 

 

You can gsap.killTweensOf(Cursor) if you want, but I'm reluctant to suggest that because it's just shielding you from the real, fundamental issue in your app (creating all those listeners). You can set overwrite: "auto" to have GSAP try to find conflicts when the new animation renders for the first time. But again, that's a band-aid here. 

 

Good luck!

Link to comment
Share on other sites

Hello @GreenSock and thank you for your suggestion 🙂. I opted to add a class to fixed elements in order to separate them from the dynamic elements. I don't have the problem anymore. What the best option to check if a gsap animation is triggered multiple times on the same element ? 

 

my code 

   const Cursor = document.getElementById('cursor')
    const fixedItems = document.querySelectorAll('a.fixed-el, button.fixed-el')
    ScaleMouse(fixedItems)
    isRoute.$subscribe(() => {
      gsap.to(Cursor, {
        scale: 1,
        duration: 1,
        ease: 'power4.out'
      })
      const newItems = document.querySelectorAll(
        'a:not(.fixed-el), button:not(.fixed-el), input, textarea, label, select'
      )
      ScaleMouse(newItems)
    })

    function ScaleMouse(Items) {
      Items.forEach((link) => {
        // On mouse enter scale the media-cursor to 2
        link.addEventListener('pointerenter', () => {
          gsap.to(Cursor, {
            scale: 2,
            duration: 1,
            ease: 'power4.out'
          })
        })
        // On mouse leave scale the media-cursor to 1
        link.addEventListener('pointerleave', () => {
          gsap.to(Cursor, {
            scale: 1,
            duration: 1,
            ease: 'power4.out'
          })
        })
      })
    }

 

Link to comment
Share on other sites

Hmm. I'm not really sure that there's a GSAP specific way, you could do console logs inside the event listeners?

On use a callback like onStart: () => console.log('start')

  • Like 1
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×