Share Posted April 1, 2022 Just a quick question: I'm trying to replace LocomotiveJS with the new ScrollSmoother plugin inside a Nuxt site. On the initial page load everything seems to work fine, but when I navigate to another page, the contents of the #smooth-content div get replaced, but the height that is set inline on the body doesn't get updated. How would I go about refreshing that? Thanks! Link to comment Share on other sites More sharing options...
Author Share Posted April 1, 2022 Ah, pausing and then unpausing seems to do the trick. Link to comment Share on other sites More sharing options...
Share Posted April 1, 2022 Hi @Born05 Would you be kind enough to make a minimal demo of your solution in CodeSandbox? I'm trying to nail down some best practices for how to handle ScrollSmoother in frameworks like Nuxt, and then put that in a blog for our users. Seeing how other people are using it would definitely help shape that as they might have some better ideas. This is how created it in Nuxt. Note that I don't have any routing. I was just trying to come up with with a way to create a ScrollSmoother that can be accessed inside any component. https://codesandbox.io/s/gsap-scrollsmoother-nuxt-js-starter-2zgxyo?file=/pages/index.vue 2 Link to comment Share on other sites More sharing options...
Author Share Posted April 4, 2022 I tried by forking your demo, and adding a new page. Unfortunately what works for me in my current project doesn't seem to work entirely inside codesandbox. You can find my demo here: https://codesandbox.io/s/gsap-scrollsmoother-nuxt-js-starter-forked-s727oq The things I did: - create an extra about page - added a header to the layout with nuxt links to home and about page - added a `gsap.client.js` plugin that registers the gsap plugins and adds convenience methods to Vue prototype - added `pageTransition` to nuxt.config.js, which uses the hooks to emit global Nuxt events for resetting, stopping or starting scroll - added `scrollSmoother` mixin, used by default layout, that sets up the ScrollSmoother instance and listens for those Nuxt events Upon routing, scroll position gets reset to 0 as I would expect, but the inline height set on the body doesn't get updated, so the about page can be scrolled way beyond its actual height. And I'm not sure why that is. 1 Link to comment Share on other sites More sharing options...
Share Posted April 5, 2022 Can you try with the latest preview of the upcoming release? ScrollTrigger: https://assets.codepen.io/16327/ScrollTrigger.min.js?v=3.10.3b ScrollSmoother: https://assets.codepen.io/16327/ScrollSmoother.min.js?v=3.10.3b (only on CodePen/CodeSandbox/local) Does that work better for you? Link to comment Share on other sites More sharing options...
Author Share Posted April 5, 2022 I might be doing something wrong here, but I tried to add those urls in CodeSandbox under `Dependencies`, but then CodeSandbox throws an error: error https://assets.codepen.io/16327/ScrollTrigger.min.js?v=3.10.3b: Extracting tar content of undefined failed, the file appears to be corrupt: "Invalid tar header. Maybe the tar is corrupted or it needs to be gunzipped?" Link to comment Share on other sites More sharing options...
Share Posted April 5, 2022 Codesandbox has trouble with those. I would just copy and paste it into a file on CodeSandbox and then import from that file. import { ScrollTrigger } from "./ScrollTrigger"; Link to comment Share on other sites More sharing options...
Author Share Posted April 6, 2022 Thanks. I tried out but that didn't solve the original problem. However, turns out I totally missed the CSS inside the layout that was setting an explicit height of 4000px. I moved that to a scoped styling block inside index.vue so the layout itself doesn't have an explicit height. Now everything is working as expected: when navigating to the about page, the scroll position is reset, and by pausing and then unpausing ScrollSmoother, the height gets recalculated and set on the body. Would be nice to have a `refresh` method on ScrollSmoother.js though, instead of pausing/unpausing. Link to comment Share on other sites More sharing options...
Share Posted April 6, 2022 It should refresh if you do ScrollTrigger.refresh() Link to comment Share on other sites More sharing options...
Author Share Posted April 6, 2022 Ah, I see. I also called that when unpausing, so that's why it was working for me. Thanks! I updated the CodeSandbox with a refresh-scroll Nuxt event in the afterEnter hook. Link to comment Share on other sites More sharing options...
Share Posted July 19, 2022 Hello folks 👋, I am trying to implement ScrollSmoother in a Nuxt3 ("nuxt": "3.0.0-rc.4") application and for now it works quite well. However when setting normalizeScroll: true and changing between pages I have the same problem as @Born05. Here is my setup for Nuxt 3: <!-- APP.VUE file --> <script setup> import { gsap } from 'gsap' import ScrollSmoother from 'gsap/ScrollSmoother' import ScrollTrigger from 'gsap/ScrollTrigger' if (process.client) { gsap.registerPlugin(ScrollSmoother, ScrollTrigger) } onMounted(() => { ScrollSmoother.create({ wrapper: "#smooth-wrapper", content: "#smooth-content", smooth: 2, effects: true, normalizeScroll: true, ignoreMobileResize: true, smoothTouch: 0.1, }) }) </script> <template> <!-- FIX CONTENT --> <!-- <li> <NuxtLink to="/">Home</NuxtLink> <NuxtLink to="/about">About</NuxtLink> <NuxtLink to="/gallery">Gallery</NuxtLink> </li> --> <div id="smooth-wrapper"> <div id="smooth-content"> <NuxtPage /> </div> </div> </template> Do you know how I can call ScrollTrigger.refresh() easily when passing to a new page ? Many thanks in advance for your suggestions ! 🙏 Link to comment Share on other sites More sharing options...
Share Posted July 19, 2022 Hey there! You'll need to take a look at Nuxt's lifecycle hooks for that.https://nuxtjs.org/docs/concepts/nuxt-lifecycle Different frameworks have difference callbacks or hooks you can pop a refresh() into. You'll need to look for the one that gets called after the DOM is loaded. In your case mounted() Quote Navigate using the NuxtLink component Same as for the client part, everything is happening in the browser but only when navigating via <NuxtLink>. Furthermore, no page content is displayed until all blocking tasks are fulfilled. Check out the component chapter to see more info on <NuxtLink> middleware (blocking) Global middleware Layout middleware Route middleware asyncData (blocking) or full static payload loading beforeCreate & created (Vue lifecycle methods) fetch (non-blocking) beforeMount & mounted Link to comment Share on other sites More sharing options...
Share Posted August 22, 2022 On 4/1/2022 at 8:45 PM, OSUblake said: Hi @Born05 Would you be kind enough to make a minimal demo of your solution in CodeSandbox? I'm trying to nail down some best practices for how to handle ScrollSmoother in frameworks like Nuxt, and then put that in a blog for our users. Seeing how other people are using it would definitely help shape that as they might have some better ideas. This is how created it in Nuxt. Note that I don't have any routing. I was just trying to come up with with a way to create a ScrollSmoother that can be accessed inside any component. https://codesandbox.io/s/gsap-scrollsmoother-nuxt-js-starter-2zgxyo?file=/pages/index.vue Hey @OSUblake! Did you ever get around to writing a blog post on best practices of using ScrollSmoother (and maybe gsap animations/scrolltriggers at large) in Nuxt projects? Link to comment Share on other sites More sharing options...
Share Posted August 22, 2022 Hiya! Sorry - Blake's been out of action for health reasons for the last while so I'm afraid not. Is there anything in particular you're stuck on? 1 Link to comment Share on other sites More sharing options...
Share Posted August 30, 2022 @Cassie I'm sorry to hear that! I hope he's okay. As for what I'm stuck on, it's similar to @BenjaminO's issue above - implementing ScrollSmoother properly in Nuxt 3. I found this Codesandbox which I think OSUBlake wrote for Nuxt 2, and was wondering if there maybe was an updated version for Nuxt 3 in a blogpost somewhere. I suppose maybe implementing it the way he's done it, and emitting a global event whenever a new page loads to pop a refresh is the best way to go about it? I tried something similar in Nuxt 2 but experienced scroll freezes for a few seconds after user started scrolling after a page nav (which is why I was so excited about the codesandbox above, but ended up migrating to nuxt 3). Unless you have a better suggestion, I'll just continue migrating my app and see if that works fine I guess Link to comment Share on other sites More sharing options...
Share Posted August 30, 2022 Hey @Aerio, I managed to create a workaround for my code (not sure that it will suits your project). Basically I am locking the scroll, then I am doing an animation for the page transition (not needed for all cases) and finally I am releasing the scroll 100ms after the ScrollTrigger.refresh() event. At first I tried something like this : ScrollTrigger.refresh(true) // with the safe parameter true ScrollTrigger.addEventListener("refresh", () => smoother.paused(false)); // smoother is SmoothScroller instance but as described in the Documentation (https://greensock.com/docs/v3/Plugins/ScrollTrigger/static.refresh()), with the safe parameter activated, it will wait for at least one requestAnimationFrame tick, and up to roughly 200ms before initiating the refresh so the user can be block if he tries to scroll during the page transition. I opted for the following approach : // app.vue <script setup lang="ts"> import gsap from 'gsap' import ScrollSmoother from 'gsap/ScrollSmoother' import ScrollTrigger from 'gsap/ScrollTrigger' import { scrollStore } from '~~/stores/piniaStore' import { delay } from '~~/assets/ts/utils' if (process.client) { gsap.registerPlugin(ScrollSmoother, ScrollTrigger) } const isLock = scrollStore() onBeforeMount(() => { if (ScrollTrigger.isTouch === 1) { ScrollSmoother.create({ ignoreMobileResize: true }) } else { ScrollSmoother.create({ smooth: 2, normalizeScroll: true }) } }) onMounted(() => { const Smooth = ScrollSmoother.get() isLock.$subscribe(() => { isLock.isReady === true ? Smooth.paused(true) : Smooth.paused(false) }) }) // const onLeave, onEnter not detailed // Check this doc : https://vuejs.org/guide/built-ins/transition.html#javascript-hooks const onBeforeLeave = (_el: HTMLDivElement) => { isLock.$patch({ isReady: true }) ScrollTrigger.getAll().forEach((t) => t.kill()) // kill all instance of ScrollTrigger except ScrollSmoother. ScrollTrigger.killAll() doesn't seem to work properly } const onAfterEnter = (_el: HTMLDivElement) => { ScrollTrigger.refresh() const promise1 = delay(100) promise1.then(() => { isLock.$patch({ isReady: false }) }) } </script> <!-- app.vue --> <template> <div id="smooth-wrapper"> <div id="smooth-content"> <router-view v-slot="{ Component }"> <!-- documentation : https://vuejs.org/guide/built-ins/transition.html#javascript-hooks --> <Transition mode="out-in" :css="false" @before-leave="onBeforeLeave" @leave="onLeave" @enter="onEnter" @after-enter="onAfterEnter" > <component :is="Component" /> </Transition> </router-view> </div> </div> </template> // utils.ts const delay = (n: number) => { n = n || 2000 return new Promise<void>((resolve) => { setTimeout(() => { resolve() }, n) }) } export { delay } // piniaStore.ts import { defineStore } from 'pinia' // I am using @pinia/nuxt, but you can manage without it https://github.com/vuejs/pinia/tree/v2/packages/nuxt export const scrollStore = defineStore({ id: 'smooth-store', state: () => { return { isReady: true } } }) 2 Link to comment Share on other sites More sharing options...
Share Posted September 27, 2022 This seems like a pretty serious problem to me given the prevalence of Nuxt - has anyone worked out a simple, workable solution to using ScrollSmoother in a Nuxt site? The "solutions" above are absurdly complex. Link to comment Share on other sites More sharing options...
Share Posted September 27, 2022 On 4/1/2022 at 7:47 PM, Born05 said: Ah, pausing and then unpausing seems to do the trick. And how would one do this? Link to comment Share on other sites More sharing options...
Share Posted September 29, 2022 Hello @thei ! My code is a bit complex because it suits my needs but you don’t need that complexity. If your on nuxt 3, basically initialize the ScrollSmoother instance onberforemount or onmounted in your app.vue then just call a scrolltrigger refresh right after the page changed. You can lock the scroll with pause() method when your transitioning from a page to another. I assume the logic will stay the same on nuxt 2. In addition there is a module named nuxt-gsap-module from Ivo Dolenc that you can use for Nuxt 2. Maybe you can handle things a bit differently with this tool. 1 Link to comment Share on other sites More sharing options...
Share Posted December 23, 2022 On 9/29/2022 at 12:27 PM, BenjaminO said: Hello @thei ! My code is a bit complex because it suits my needs but you don’t need that complexity. If your on nuxt 3, basically initialize the ScrollSmoother instance onberforemount or onmounted in your app.vue then just call a scrolltrigger refresh right after the page changed. You can lock the scroll with pause() method when your transitioning from a page to another. I assume the logic will stay the same on nuxt 2. In addition there is a module named nuxt-gsap-module from Ivo Dolenc that you can use for Nuxt 2. Maybe you can handle things a bit differently with this tool. Every thing work well but i have only one issue . the issue with NuxtLayout. <div id="smoother-wrapper" ref="smoother__wrapper"> <div id="smoother-content" ref="smoother__content"> <div class="app_container"> <NuxtLayout> <NuxtPage :transition="{ name: 'my', mode: 'out-in', onBeforeEnter }" /> </NuxtLayout> </div> </div> </div> ,when i put without nuxtlayout it's work . <div id="smoother-wrapper" ref="smoother__wrapper"> <div id="smoother-content" ref="smoother__content"> <div class="app_container"> <NuxtPage :transition="{ name: 'my', mode: 'out-in', onBeforeEnter }" /> </div> </div> </div> so how should we make it in top of NuxtLayout ! Link to comment Share on other sites More sharing options...
Share Posted December 23, 2022 Hi, Is a bit difficult to troubleshoot without a minimal demo, please try to provide one. We have this starter templates so you can fork it and accommodate it to fit you project's specifications: https://stackblitz.com/edit/nuxt-starter-q72fhs?file=app.vue The only thing I can suggest is to use a ref to store the ScrollSmoother instance and refresh it when the route changes. Perhaps use the mount hook to create the ScrollSmoother instance and revert it when it gets unmounted. If you create a reactive property using the router's path those hooks should trigger on every route change. Also I see that you are using transitions. You can also use the JS hooks for the transition component in order to create and revert a GSAP Context instance. Hopefully this helps. Happy Tweening! Link to comment Share on other sites More sharing options...
Share Posted December 24, 2022 Thanks , the main problem from the #smooth-content when i put height like 4000px it's work but when i put 100% it's not so how can i do it !? ofcourse all my content not absolute . Link to comment Share on other sites More sharing options...
Share Posted December 24, 2022 6 hours ago, KhaledOghli said: Thanks , the main problem from the #smooth-content when i put height like 4000px it's work but when i put 100% it's not so how can i do it !? ofcourse all my content not absolute . somthing like this ! https://stackblitz.com/edit/nuxt-starter-gz2tkz?file=README.md if anyone figure out what the problem is ? Link to comment Share on other sites More sharing options...
Share Posted December 24, 2022 ScrollSmoother typically needs its wrapper element at the root (inside <body>), but it looks like you've got it tucked inside of another element with an id of __nuxt. So when ScrollSmoother's wrapper element is set to position: fixed, it takes it out of the document flow, thus your __nuxt element gets a height of 0. Try defining your wrapper as that __nuxt element: wrapper: "#__nuxt", Link to comment Share on other sites More sharing options...
Share Posted December 25, 2022 8 hours ago, GreenSock said: ScrollSmoother typically needs its wrapper element at the root (inside <body>), but it looks like you've got it tucked inside of another element with an id of __nuxt. So when ScrollSmoother's wrapper element is set to position: fixed, it takes it out of the document flow, thus your __nuxt element gets a height of 0. Try defining your wrapper as that __nuxt element: wrapper: "#__nuxt", Save Oh, Thank you so much for the explanation and help. its work. Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now