Jump to content
Search Community

ScrollTrigger and Vue-router issue (start and stop bug)

acantoroBB test
Moderator Tag

Recommended Posts

Hi,

 

I'm new to use Scrolltrigger in SPA. For my project I'm using vue and vue-router, and I have some issues with Scrolltrigger when I navigate to another pages.

 

The start and end values from my scrolltriggers are set to the height of the previous page,  and it works only if I manually reload the page.

I tried the ScrollTrigger.refresh() and ScrollTrigger.kill() methods on mounted and beforeDestroy Vue's lifecycle as recommended in the most common issues article, but it's not working (https://greensock.com/st-mistakes/#navigating-back).

 

I made a sample in a sandbox project but I don't succeed to reproduce the error.

 

Thank you for your help.

Link to comment
Share on other sites

Hi, welcome to the GreenSock forums and thanks for being a club member and supporting GSAP!!!

 

Sorry to hear that you're experiencing this issue. As you mentioned I tried a simple set up in codesandbox and in my local environment but I'm unable to reproduce the issue.

 

Perhaps try storing the GSAP instance instead the ScrollTrigger instance in the component and use that to reference it in the beforeDestroy hook, something like this:
 

import { gsap } from "gsap";

export default {
  mounted() {
    this.t = gsap.to(this.$refs.aboutImage, {
      scrollTrigger: {
        trigger: this.$refs.imageContainer,
        start: "top top",
        end: "+=200%",
        pin: true,
        scrub: 0.5,
      },
      x: 200,
      y: 100,
      duration: 1,
    });
  },
  beforeDestroy() {
    this.t.kill();
  },
};

Perhaps something else in your code or another package in your app could be causing this issue.

 

If you can't solve it, perhaps try using a specific <div> element as the scroller. Wrap all your app in that element, give it a height of 100vh and overflow: auto. Like that you can point that as the scroll element in ScrollTrigger:

gsap.to(this.$refs.element, {
  scrollTrigger: {
    scroller: "#parentElement"
  }
});

I know that using the id selector is not the best idea but otherwise you'll have to either add it to a VueX store or pass it down as a prop to all the elements that use it or get fancy with this.$el.parent in the child components and the ones down the component tree. Also since that element is likely to be mounted just once in the app's lifecycle, it shouldn't become an issue down the line.

 

Happy Tweening!!!

  • Like 2
Link to comment
Share on other sites

Thank you for responding, despite I don't share any sandbox or codepen.

 

I had use data to store my gsap instance during mount, kill it and set data to null it during the beforeDestroy event.

 

data() {
    return {
      marqueeScrollTrigger: null,
    }  
},
methods: {
    scrollAnim() {
      this.marqueeScrollTrigger = gsap.to(this.$refs.inner, {
        xPercent: -65,
        scrollTrigger: {
          trigger: this.$refs.marquee,
          start: "top bottom",
          end: "top top",
          scrub: 0,
          //markers: true,
          //scroller: this.$el.parent,
        }
      })
    },
},
mounted() {
  this.scrollAnim();
},
beforeDestroy(){
    this.marqueeScrollTrigger.kill()
    //this.marqueeScrollTrigger.scrollTrigger.kill(true)
    this.marqueeScrollTrigger = null
}

 

I also thought maybe there is a problem with a dependency, but I don't have much and I can't see which can cause the issue. I'm stuck and I really don't know why it works on sandbox or blank project but not in this.

 

"dependencies": {
    "@vue/cli": "^4.5.12",
    "core-js": "^3.6.5",
    "embla-carousel": "^4.3.2",
    "gsap": "file:gsap-bonus.tgz",
    "normalize.css": "^8.0.1",
    "vue": "^2.6.11",
    "vue-router": "^3.2.0"
  },

 

EDIT: I created a new project with those dependencies and devDependencies and it still works.

 

EDIT2: I also browse some topics with same problem with other framework (i.e React) and I tried the .refresh() method on mounted event and it doesn't work too.

 

Link to comment
Share on other sites

Try removing the GSAP instance from the data object. Animations are not exactly reactive data in the realm of reactive frameworks (Vue, React, etc.) and just use this.marqueeScrollTrigger directly in the mounted hook to keep track of the instance and be able to kill it afterwards.

 

The problem could be that the initial rendering by the browser is taking longer than the JS execution, therefore ScrollTrigger is doing all the calculations and after that the content somehow is shifting, you could check the height of the body element or the main parent element before creating the ScrolLTrigger instance and also inside a setTimeout or a delayedCall method, and see if there are differences. You could inspect in devtools and see in the performance tab if there is a long paining thread there.

 

Honestly I don't see anything in your dependencies that seems suspicious.

 

Happy Tweening!!!

  • Like 1
Link to comment
Share on other sites

I tried removing gsap from data and I added a setTimeout to this.marqueeScrollTrigger.refresh() and it seems to work. 

It's not a proper way do it but it's a good start to test where is the problem, I guess it's as you said maybe a problem with rendering and JS execution.

 

Here is my code now :

 

mounted() {
  let self = this;
  
  this.marqueeScrollTrigger = gsap.to(self.$refs.inner, {
    xPercent: -65,
    scrollTrigger: {
      trigger: self.$refs.marquee,
      start: "top bottom",
      end: "top top",
      scrub: 0,
  	}
  })

  setTimeout(function(){
  	self.marqueeScrollTrigger.scrollTrigger.refresh()
  }, 10); 
},
beforeDestroy(){
  this.marqueeScrollTrigger.kill()
}

 

Link to comment
Share on other sites

  • 6 months later...

I read all the articles on this and similar problems on this forum and on stackoverflow. and YES setTimeout working, but this is not the answer.

I was also confused that the problem does not affect a large number of people, but they describe almost the same situations, when vue + router + gsap + scrolltrigger stops to work, when you go through the pages (routes) and return to previous one with animations (animations dont work in this case).

so, guys, first of all look at <transition> above <router-view>. this is the problem, when you have components from previous page AND next page at the same time, and ScrollTrigger calculates the values (offsetTop) in that time

  • Like 1
Link to comment
Share on other sites

5 minutes ago, OSUblake said:

If you have a transition component, then mounted is going to fire before the page is ready. You should probably tap into some of the JavaScript hooks it provides to manage ScrollTrigger creation and killing.

https://vuejs.org/v2/guide/transitions.html#JavaScript-Hooks

 

yep. I just wrote this my previous comment so that people do not spend hours figuring out the basis of problem (like me :)

in my case i even didnt have transition animations! i had <transition name="test"> without css. so i even didn't see delays between components changing :( but vue already worked differently...

Link to comment
Share on other sites

  • 3 months later...
  • 1 month later...

I also have a similar problem. I use Vue router to jump the page. The size of the pin spacer box on the first page will be retained to the second page. This may be due to single page application. I don't know.

I tried @Rodrigo's method:

On 4/15/2021 at 5:20 AM, Rodrigo said:
beforeDestroy() {
    this.t.kill();
  },

,but failed
My solution is:

deactivated() {
    location.reload()
  }

But I think there may be disadvantages. If there is a better way, please reply to me

Link to comment
Share on other sites

15 hours ago, OSUblake said:

 

That doesn't sound like a good approach, reloading the page. Can you make a minimal demo on CodeSandbox that shows the issue? Thanks!

 

Thank you for your reply

minimal demo is here:https://codesandbox.io/s/minimal-demo-forked-t7psos?file=/src/App.vue

The location of the footer that jumps from the home page to the about page will not change because the home page pin is set to true

This demo is a little bad because I haven't used codesanbox before

Link to comment
Share on other sites

If you're using <keep-alive>, then you need kill your triggers in deactivated. Also, you should never pin the first element in a <template>, so add a wrapper if you want to do that. And keep in mind that when you do something like gsap.utils.toArray("section"), it's going to search the entire document for section tags, and not just what's in your template HTML.

 

https://codesandbox.io/s/minimal-demo-forked-ulzusv?file=/src/App.vue

 

  • Like 2
Link to comment
Share on other sites

Thank you for your reply.
When I searched before, I also saw that a wrapper should be added outside the element, so I .Banner has been added .pin-container.I didn't expect to add the first element in the template. Thank you very much for your correction.
However, there is still a problem that existed before. When switching to the about page and then switching back to the home page, page scrolling will cause page exceptions.
I added 

ScrollTrigger.refresh()

 in the activated of each page.

It's solved, but I don't know if it's a good way

 

Link to comment
Share on other sites

We dont see example, so cant say anything.

“refresh” is a bad way. Something wrong.

open dom inspector in your browser and try to see whats happen with dom tree when you change pages. By default you must see immediate update of dom tree 

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...