Jump to content
GreenSock

Search In
  • More options...
Find results that contain...
Find results in...
yannick

Ideal vue.js setup for playing and reversing timelines

Recommended Posts

How do you setup a vue component to be able to play and reverse a timeline upon a certain event?

When I setup a method containing the timeline instance it wll be declared everytime the method is called. The reverse function won't work in this case.

Link to post
Share on other sites

Hi,

 

I don't know if this is the ideal way of doing it, but the best approach I can think of is to create a reference to the timeline instance in the data() callback:

 

data() {
  return {
    tween: new TimelineLite({ paused: true })
  };
},

 

Then in the mounted hook, add the instances to the timeline:

 

mounted: function() {
  this.tween
    .to(this.$refs.appLogo, 2, {
      rotation: 360
    })
    .reverse();
}

 

And finally in the methods object define a method to play/reverse the instance:

 

methods: {
  toggleLogoTween: function() {
    this.tween.reversed(!this.tween.reversed());
  }
},

 

Here is a live reduced sample:

 

https://codesandbox.io/s/l261n378km

 

Happy Tweening!!

  • Like 6
Link to post
Share on other sites

Thanks a lot. That works exaclty how expected.

 

Just to clarify.

Why do you add the reverse() function at the end of the mounted hook? Will it add the ability to reverse the timeline in general?

 

If I'm not mistaken the methods is the same as.

if ( !this.textTl.reversed() ) {
   this.textTl.play()
} else {
   this.textTl.reverse()
}

Am I correct?

  • Like 2
Link to post
Share on other sites

You're welcome.

 

Well is just a pattern that you'll see quite a bit here in the forums and some bits I gathered throughout my time here.

 

First unless is necessary I always create Timeline instances paused, because otherwise the time is already running and the playhead is moving forward. Granted, normal JS execution to add the instances might take only a few milliseconds but in some cases that could cause some unexpected behaviour. Now I'll jump forward to this:

 

tl.reversed( !tl.reversed() );

 

Reversed is a getter/setter of the reverse status of a GSAP instance. By default all GSAP instance are created and going forward, therefore by default reversed() returns false. Since I'm using reversed() as a setter (by passing the opposite value) I need that the reverse status of the timeline to be true. Now since I created the timeline paused the playhead won't go anywhere unless I change that, hence I add a reverse() call at the end of the timeline. Now the timeline is paused, so I'm telling the timeline: "Go from being paused to play backward", but since the timeline is at zero seconds and negative time doesn't exists (although @GreenSock and/or @OSUblake might be working on that ;)) the timeline stays put at zero seconds and the reversed() value is true. Then on the first click (or any other event that triggers it) I toggle the reversed() value to false, which tells the timeline to go forward and so forth.

 

Basically is just a way of doing it without the conditional block in it, which saves a tiny amount of time and a couple of lines of code.

 

Hopefully this makes things more clear about it.

 

Happy Tweening!!!

  • Like 3
Link to post
Share on other sites

i am currently managing my timelines like this (like @Rodrigo suggested above). i just noticed this "unknow component" text using the vueDev tool. i mean, everything is working but still, i wonder about this.. 

 

ehEm3c4.png

Edited by dnvdk
needed to clarify
Link to post
Share on other sites

Hard to say without seeing your code. Are you adding animations to the data object?

 

I normally put animations on the instance itself. The data object is for reactive stuff. Adding animations to it creates more overhead.

  • Like 3
  • Thanks 1
Link to post
Share on other sites
6 hours ago, OSUblake said:

Are you adding animations to the data object?

yes i was!

 

6 hours ago, OSUblake said:

Adding animations to it creates more overhead.

..and thanks a lot for pointing that out.


👇 now my code looks like this and works as intended 👇
 

🏠 Home.vue

<template>
  <div class="home">

    <div class="px-3 py-3 is-fixed-1" v-if="isSignedIn">
      <figure class="image is-48x48">
        <router-link to="/control">
          <img class="is-rounded" :src="user.photo" />
        </router-link>
      </figure>
    </div>

    <section class="fill-viewport-1">
      <div ref="separador1" class="separador-1"></div>
      <div ref="nombre" class="nombre">
        <img src="@/assets/images/nombre.svg" alt="🖼️" />
      </div>
    </section>

    <div ref="mouseContainer" class="mouse-container">
      <div class="mouse">
        <div class="wheel"></div>
      </div>
    </div>
    
  </div>
</template>

<script>
import { mapState } from "vuex";
import { homeTweens } from "../mixins/homeTweens";

export default {
  mixins: [homeTweens],
  name: "Home",
  computed: {
    ...mapState("auth", ["user", "isSignedIn"])
  }
};
</script>

🧙‍♂️ homeTweens.js

import { gsap } from "gsap";

let introTl = gsap.timeline({
  paused: true,
});

export const homeTweens = {
  mounted: function() {
    introTl
      .from(
        this.$refs.separador1,
        {
          duration: 0.8,
          xPercent: -100,
        }
      )
      .from(
        this.$refs.mouseContainer,
        {
          duration: 0.9,
          yPercent: 100,
          autoAlpha: 0,
        },
        "<"
      )
      .from(
        this.$refs.nombre,
        {
          duration: 0.5,
          yPercent: 10,
          autoAlpha: 0,
        },
        "<"
      );
    this.playTimeline();
  },
  methods: {
    playTimeline() {
      introTl.play();
    },
  },
  beforeRouteLeave(to, from, next) {
    introTl.reverse().eventCallback("onReverseComplete", function() {
      introTl.clear();
      next();
    });
  },
};

now.. i wonder if there is a better way to achieve the same goal.

thanks again for reading me 🧙‍♂️🤓

Link to post
Share on other sites

I would put the timeline on the instance using this.

 

export const homeTweens = {
  mounted() {
    
    this.introTl = gsap.timeline()    
      .from(
        this.$refs.separador1,
        {
          duration: 0.8,
          xPercent: -100,
        }
      )
      .from(
        this.$refs.mouseContainer,
        {
          duration: 0.9,
          yPercent: 100,
          autoAlpha: 0,
        },
        "<"
      )
      .from(
        this.$refs.nombre,
        {
          duration: 0.5,
          yPercent: 10,
          autoAlpha: 0,
        },
        "<"
      );
  },
  beforeRouteLeave(to, from, next) {
    this.introTl.reverse().eventCallback("onReverseComplete", function() {
      this.introTl.kill();
      this.introTl = null;
      next();
    });
  },
};

 

  • Like 4
Link to post
Share on other sites

 

5 hours ago, OSUblake said:

I would put the timeline on the instance using this.

 

i did like you suggested and i get this error:

 

JP08Y3B.png

 

i did commented these 2 lines and the error is gone, expected behavior,  but yeah... no kill, no clear..

 

5 hours ago, OSUblake said:

this.introTl.kill(); this.introTl = null;

 

Edited by dnvdk
typo error
Link to post
Share on other sites

Oh, it would need to be an arrow function.

this.introTl.reverse().eventCallback("onReverseComplete", () => {
      this.introTl.kill();
      this.introTl = null;
      next();
    });

 

  • Like 1
  • Thanks 1
Link to post
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.

×