pirony / nuxt-gsap

Easy GSAP (https://greensock.com) integration with Nuxt.js
MIT License
16 stars 2 forks source link

Nuxt GSAP ScrollTrigger possible conflict import w multiple components #8

Open pdub888 opened 3 years ago

pdub888 commented 3 years ago

Nuxt.js @ v2.14.6

Issue: buggy/broken ( items might be tweening multiple times/multiple points ) when activated in v-for rendered components.

I think my question/issues has to do with this.$gsap being global - I register it within each of my vue files ( i have to or else it throws an error ). //this.$gsap.registerPlugin(ScrollTrigger);

On single vue files, ScrollTrigger works well. But in the instance where I need to add a series of timeline animations to the utils array contained within a component and there are multiple components, it does not.

A nuxt component's lifecycle fires mounted() when the DOM element has been added...and when I added it without the below code, it completely broke - and my guess is that there was multiple instances?? of either a timeline or multiple instances of gsap ( i'm not even sure at this point ) that was competing with one another.

Since I have multiple components, I wrote kind of a 'hack' to first see if this components parent has been mounted - ( meaning all the v-for nested components are mounted/rendered ) - and then second see if it's the first instance ( using an id generated by index ) of this component, and if it is, only create a timeline instance with a forEach array of my classes I need to animate. It looks to be working, for now, but I'm pretty confident that there is a much better way to handle timelines/utils/global gsap calls. Can someone talk me off a ledge and say what i'm doing is OK ( because of the way gsap works? ) or suggest a different solution. I know it's a tough case ( and also partly/mostly a nuxt question ) - thanks:

// parent - include id for each child/FeaturedSection and also include a parentmounted ( heyo )
//prop that I watch in children component
<template>
<section>
<FeaturedSection v-for="(item,index) in mycontent" :id="index" :key="item._uid" :parentmounted="fullyMounted"/>
</section>
</template>

// child - watch for prop change to determine when parent is mounted ( thus all instances of this particular component ) 
// here is the major hack/problem - listen for first instance of component to create a forEach loop to find all instances of component using class
// if I don't do this, it must fire 3 times, and either creates 3 timelines?? 
//or 3 global gsap objects ? or duplicates functions in the gsap.utils.toArray

<! -- FeaturedSection/child component - say I have 3 of these, but each one fires mounted I think -->
<template>
<section>
<component v-for="mycomponent in mycontent" class="feat-component" :key="mycomponent._uid" :blok="mycomponent" :is="mycomponent.component" :id="id"></component>
</section>

</template>

<script>
    import { ScrollTrigger } from "gsap/dist/ScrollTrigger.js";
    export default {
        watch: {
          parentmounted: function(newVal, oldVal) { // watch it
              // hack way of determining that the parent has loaded then only create one instance/one timeline of gsap
            let st = this.$gsap.registerPlugin(ScrollTrigger);
            let gsp = this.$gsap;
              gsp.utils.toArray(".feat-component").forEach((blk,index) => {
                if(this.id==0 && index != 0){
                      let tl = this.$gsap.timeline({
                          scrollTrigger: {
                              trigger: blk,
                              markers: true,
                              scrub:true
                          }
                      });
                      tl.from(blk, {
                          duration: 2,
                          y:"+400",
                          ease: "expo.out"
                      });
                }
              });
            }
         }
    }
</script>
notflip commented 9 months ago

Wouldn't this create a timeline for each item in the array? Is that the required effect?