Jump to content
Search Community

How to stagger dynamic content with ScrollTrigger in Vue?

JayLow test
Moderator Tag

Recommended Posts

Hi All, 

Looking for some advice on this. 

First, here is a codesandbox link that is a minimal demo of my issue. https://codesandbox.io/s/sad-dirac-p04pv?file=/src/components/textSpan.vue

 

Let me try to explain. The textSanitizer component serves as a serializer for a WYSIWYG from a CMS. Every type of text has its own respective  component to render that type of text (heading, paragraph, textSpan, etc). These each have their own unique animations, which I call using refs in the mounted hook. What I would like to accomplish, is have all of these linked together to stagger on one scroll trigger, as opposed to each having its own. That way when someone scrolls to a text block, they cant solely trigger the first element without triggering the rest.

I was thinking this would involve setting up a timeline on the textSanitizer component, and having each child append itself once it renders? Not sure if this is the right path, but just an idea

 

Link to comment
Share on other sites

@OSUblake Selector utility looks promising. Docs say React and Angular refs though. Is it setup to work with Vue? I've believe I've tried the second option, but I've had cases where it will try to access the ref before it is defined. I might try an emit where the child passes its animation up on mounted. Will investigate more though. Thanks for the help

Link to comment
Share on other sites

2 hours ago, JayLow said:

Selector utility looks promising. Docs say React and Angular refs though. Is it setup to work with Vue?

 

It works with any element. The docs show React and Angular because the element isn't provided directly like it is with Vue (this.$el).

 

2 hours ago, JayLow said:

I've believe I've tried the second option, but I've had cases where it will try to access the ref before it is defined.

 

Do you have a demo of that? It might be because you need to wait until the $nextTick. Hard to say without seeing a demo.

 

 

Link to comment
Share on other sites

@OSUblake

After a lot of testing, I think I got it working reliably. In cases where the child components mounted before the parent, the selector utility worked fine. However, I had cases where the opposite occured, and the mounted of the parent ran before any of the children, which led to nothing returning with the selector utility. I couldnt get $nextTick working reliably either. I had some cases where it worked fine, others where children were still rendering by the time it rain. 

What I ended up doing, was create a timeline on the parent component in its created() hook, and have each child pass up its tween in an $emit listener, which adds it to the parent timeline and kills the childs scrolltrigger. That way, children can work by themselves or be merged with a parent if its available.

 

The parent sets up a scrolltrigger on its mounted() hook because thats when the DOM is available

 

Example of child:
 

  props: {
        text: {
            type:String,
            required:true
        }
    },

    

    mounted() {

      console.log('child mount')
     this.animation =  split(this.$refs.text)
     this.$emit('child', this.animation)
    },

    data() {
      return {
        animation:{}
      }
    },

Example of parent:
 

export default {
  data() {
    return {
      timeline: null,
      childElements:[]
      
    };
  },

  methods: {
    fillTimeline(el) {
      this.timeline.add(el.progress(0).pause(0).delay(0).play(0), '<+=.3')
    },


    addchild(anim) {
      anim.trigger.kill()
      anim.animation.pause(0)
      

      this.fillTimeline(anim.animation)
    }
  },

  created() {
    this.timeline = timelineInit();
  },

  mounted() {
    timelineTrigger(this.$refs.trigger, this.timeline)
  }

 

Link to comment
Share on other sites

10 minutes ago, JayLow said:

In cases where the child components mounted before the parent, the selector utility worked fine.

 

You should probably wait until the next tick. See if this works. If so, I'll add it to the selector docs.

mounted() {
  this.$nextTick(() => {
    // everything should be rendered    
  });
}

 

Link to comment
Share on other sites

4 minutes ago, OSUblake said:

 

You should probably wait until the next tick. See if this works. If so, I'll add it to the selector docs.


mounted() {
  this.$nextTick(() => {
    // everything should be rendered    
  });
}

 

No it does not work for me, selector utility comes back empty

Link to comment
Share on other sites

36 minutes ago, OSUblake said:

Do you think you can put a simple demo of the problem on Codesandbox? I'd like to see if there's a way to fix it.

Apologies, I tried  making a code sandbox demo. I structured it very similarly to my project, and works the right way on the sandbox, I'll have to look more into it

Link to comment
Share on other sites

Hmm.... are you using Nuxt? Not sure what's going on because according to Vue's docs, the DOM should be ready in the next tick.

 

Quote

Note that mounted does not guarantee that all child components have also been mounted. If you want to wait until the entire view has been rendered, you can use vm.$nextTick inside of mounted:


https://vuejs.org/v2/api/#mounted

 

  • 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.
×
×
  • Create New...