Jump to content


Tweening via Vue.js reactive data properties -- gsap becomes limited in power due to not full access to DOM?

Warning: Please note

This thread was started before GSAP 3 was released. Some information, especially the syntax, may be out of date for GSAP 3. Please see the GSAP 3 migration guide and release notes for more information about how to update the code to GSAP 3's syntax. 

Recommended Posts

I'm learning both vue.js and greensock and looking to understand how to use these two wonderful tools in tandem.


The position: as I understand it, the point of using vue.js is that you don't need to manually update the dom.

Instead, you bind data properties and vue then handles dom updates for you. All you do is change the data property.


I have explored using TweenLite and passing in as the first argument something from the reactive data properties of a vue component, e.g.

    <svg width="20rem" height="20rem" viewBox="0 0 100 100">
         <rect :x="rect1.x" :y="rect1.y" :width="rect1.w" :height="rect1.h" :fill="rect1.f" />
         <circle id="circle1" class="fill-dark-blue" cx="60" cy="60" r="10" />

export default {
	data() {
        return {
            // below are not dom elements, but are bound to dom elements by vue
            rect1:  { x: 14.696, y: 13.414, w: 47.574, h: 30.602, f: '#ebebeb' },
            // ...

// e.g. in mounted():
TweenLite.to(this.rect1,  1.0, { w: 10, h: 50,        f: '#ffd700', ease:Power4.easeOut  });


What this is doing is tweening the data property which vue then reactively updates each time the data property is changed by TweenLite.

i.e. we're tweening a vue data property, which is then reactively updated on each change.  It all works fine, which is very cool.


However, I cannot use, e.g. { className: 'light-yellow' } in the TweenLite vars, the reason being that to accomplish that animation, gsap will attempt to do it by first sniffing the css properties, then adding a style tag (as seen in action on the excellent intro to greensock short video on this site).  That does not work because (my guess) the selector passed to gsap is not actually a dom selector but the vue data property. Hence, gsap doesn't seem to be able to get the dom hook so can't apply the style tag. At least, that's my diagnosis of why it is not working.


In contrast, I can get the className animation working by doing this:


TweenLite.to('#circle1', 1.0, { className: 'fill-light-blue' });


What the above is doing is going into the dom directly via an id tag and so bypassing vue's data binding.

The problem is that in this case, if I have a complex svg, I can no longer benefit from vue's ability to bind into anywhere in the dom simply by updating a data property. I'll have to get into dom navigation. This seems wrong.


What does all this mean?  Does it mean quite simply that if I want to tween vue data properties (for the benefit of not having to navigate the dom) that the feature set I am going to have available to me from gsap is going to be necessarily limited?  I'm not entirely sure at this point how much of TweenLite & Max's power is going to be curtailed by this pattern, as I'm still learning.  At this point I really want to grab a couple of good patterns for vue & gsap and get plenty of practice. Just need to settle on a limited set of patterns to practice with.  


The goal I have in mind here is, say, making a fairly complex svg and animating its component parts with greensock, via vue. 


Am I doing this right ?


Thank you very much for discussion.

Edited by miwal
add tag
Link to comment
Share on other sites

I found that vue does have a way to access the dom directly, via a $refs property on the vue instance.


You can set these in your vue templates, which are comparable to ids but are not in the actual rendered dom.  They give you back, inside of vue, a reference to the actual dom element.   That can achieve what seems needed here, letting TweenLite do its stuff, and avoiding inconvenience of verbose manual dom navigation or setting a ton of ids.


I'm going to explore that pattern and my question still stands in the general area of good patterns via which these libraries can work together, perhaps specifically in the context of svgs.    Thanks for your interest.




  • Like 1
Link to comment
Share on other sites

Great, thanks for reporting back. I'm not very familiar with Vue yet, so I can't offer much but I know that Sarah Drasner is a big advocate for both Vue and GSAP (and using them together of course), so I'm confident it's entirely doable. In fact, if I remember correctly I think some of the examples on the Vue site are (or will be) using GSAP. 


And of course GSAP and SVG animation go together like peanut butter and jelly ;)


Happy tweening!

Link to comment
Share on other sites

Hi there! 


My name is Sarah, I'm on the Vue core team and do a lot of work with Vue and SVG animation using GSAP. Yep, you're on the right track, refs are the way to target these elements though technically it still works to target an id or class as usual. However, there are some key pieces in here that I want to separate out in case it's helpful to you, because really the sky's the limit! And they play so well together:


1) The way that animation and rendering work, you are *always* going to be touching the DOM in the case of animation, this can't only happen in the virtual DOM (something that people miss about React, too, even when looking at libraries like React-Motion)

2) There's a way to interpolate numbers that then update the DOM by transitioning state, and then there is accessing the DOM directly. You can use Vue and GSAP for both. I rewrote the docs example to use GSAP for our transitioning state example here: https://vuejs.org/v2/guide/transitioning-state.html#Animating-State-with-Watchers, but the way you're working with the DOM nodes and watchers, you may be more interested in this chart I wrote with where I'm spinning up SVG DOM nodes with directives, which is similar to what you're doing. In other words, you can use Vue and GSAP to interpolate number or values, and then apply that to a style binding, OR you can just update the fill in GSAP by targeting the element directly, that will still work. There is even a relative HSL tween that gsap offers if that's your jam :)

3) You might also want to set things up with a transition component, which offer some javascript hooks for beforeEnter, enter, and leaving states: (I have a bunch of pens that do this but this is probably the simplest Vue Book Content Typer) The nice thing that the transition component offers you is an ability to coordinate one thing entering and another leaving, with transition modes. They're pretty spectacular. You will also be given FLIP under the hood with the transition-group component.

4) You can also plug directly into the mounted lifecycle hook, as you can see here: Vue Weather Notifier Pen. This way you can activate an SVG animation on the component as soon as it's in the DOM. You can also see in this pen I'm changing opacity, using drawSVG, changing color, rotating, you name it- it's all possible on SVG elements and you don't *have* to put them in data. Though there's nothing wrong with transitioning state that way either.


I also wrote this article that should help you: https://css-tricks.com/intro-to-vue-5-animations/

And have this open source repo which is a whole workshop just about vue and svg animations: https://github.com/sdras/animating-vue-workshop


Please feel free to ask any questions as well. Thanks! 

See the Pen YNpaoJ by sdras (@sdras) on CodePen


See the Pen MJedjd by sdras (@sdras) on CodePen


See the Pen OWZRZL by sdras (@sdras) on CodePen


  • Like 12
  • Thanks 2
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.