iekgithub Posted October 10, 2024 Posted October 10, 2024 Hi I have a new question about using gsap with Vue. I need to create a combined animation for two components using one timeline. There is a <h2> element moving from the left and then li elements falling from the top. I've achieved this when I was working with one component. But then I needed to add the same effect to a lower component with the same structure. And I wanted them to stack, so the second Component starts its animation after the first stack ends. And I don't udestand how to create a shared instance of the timeline so both components could use it. I tried to use Pinia to create a shared instance but it didn't solve my problem. 1) The first component which was animated successfully // The first component which was animated successfully <script setup lang="ts"> const scopeRef = ref(); let ctx : gsap.Context | undefined; onMounted(() => { ctx = topDescriptionGsap(scopeRef); }) onUnmounted(() => { if (ctx) { ctx.clear() } }) </script> <template> <div v-if="screenStore.getScreenState === selectorState.DeleteImages" class="wrapper" ref="scopeRef" > <h1> Просмотреть изображения в базе </h1> <article class="TopDescriptionSection"> <h2 class="h-description-target"> Возможности панели управления: </h2> <ul class="TopDescriptionSectionUlAlignLeft"> <li v-for="li in arrayStore.getBrowseArray" class="li-description-target" > {{li}} </li> </ul> </article> </div> <div v-else class="wrapper" > <h1 class="presentation"> Загрузить новые изображения </h1> <article class="TopDescriptionSection"> <h2 class="h-description-target"> Правила для корректной загрузки: </h2> <section class="TopDescriptionSectionUlAlignLeft"> <ul> <li v-for="li in arrayStore.getRulesArray" class="li-description-target" > {{li}} </li> </ul> </section> </article> </div> </template> 2) a function for animating the first component. A create a timeline here, and I want to share this timeline for usage in other components. At this point everything works fine. import {Ref} from "vue"; import gsap from "gsap"; export function topDescriptionGsap(scopeRef : Ref<any, any>) : gsap.Context { let ctx = gsap.context((self) => { const li_targets = gsap.utils.toArray('.li-description-target'); const h_target = document.querySelector('.h-description-target'); const timeline = gsap.timeline(); timeline .from(h_target, { opacity: 0, xPercent: -40, duration: 0.5 }) .from(li_targets, { opacity: 0, yPercent: -50, stagger: 0.3 }) }, scopeRef.value); return ctx } 3) This is the component which I want to animate with the same timeline from first example. So animations would be stacked. <script setup lang="ts"> import {useImageSizeBufferStore} from "@/pinia/ImageSizeBufferStore.ts"; import {kb_to_mb_converter} from "../structs/tool_functions/data_managing_functions/kb_to_mb_converter.ts"; const imageBufferStore = useImageSizeBufferStore(); </script> <template> <article class="TopDescriptionSection"> <h2 class="h2-table-buffer-gsap">Информация о изображениях:</h2> <section class="TopDescriptionSectionUlAlignLeft"> <ul> <li class="li-table-buffer-gsap"> Всего изображений обнаружено : {{ imageBufferStore.getTotalImages }} </li> <li class="li-table-buffer-gsap"> Общий размер всех изображений в базе : {{ imageBufferStore.getBufferSize }} кб ~ {{ kb_to_mb_converter(imageBufferStore.getBufferSize) }} мб </li> </ul> </section> </article> </template> How can I do that? My thoughts I should move ctx one level up, so both components would be captured in one context.
GSAP Helper Posted October 10, 2024 Posted October 10, 2024 Without a minimal demo, it's very difficult to troubleshoot; the issue could be caused by CSS, markup, a third party library, a 3rd party script, etc. Would you please provide a very simple CodePen or Stackblitz that illustrates the issue? Please don't include your whole project. Just some colored <div> elements and the GSAP code is best. See if you can recreate the issue with as few dependencies as possible. Start minimal and then incrementally add code bit by bit until it breaks. Usually people solve their own issues during this process! If not, at least we have a reduced test case which greatly increases your chances of getting a relevant answer. See the Pen aYYOdN by GreenSock (@GreenSock) on CodePen. that loads all the plugins. Just click "fork" at the bottom right and make your minimal demo: Using a framework/library like React, Vue, Next, etc.? CodePen isn't always ideal for these tools, so here are some Stackblitz starter templates that you can fork and import the gsap-trial NPM package for using any of the bonus plugins: React (please read this article!) Next Svelte Sveltekit Vue Nuxt Please share the StackBlitz link directly to the file in question (where you've put the GSAP code) so we don't need to hunt through all the files. Once we see an isolated demo, we'll do our best to jump in and help with your GSAP-specific questions. ✅
Rodrigo Posted October 10, 2024 Posted October 10, 2024 Hi The best approach I can think of is to create the timeline on a parent component and then listen to an event in the parent component and create child instances on the timeline, this event can be emitted from the child component as explained here in the Vue docs https://vuejs.org/guide/components/events.html#emitting-and-listening-to-events Hopefully this helps Happy Tweening!
iekgithub Posted October 10, 2024 Author Posted October 10, 2024 1 hour ago, Rodrigo said: Hi The best approach I can think of is to create the timeline on a parent component and then listen to an event in the parent component and create child instances on the timeline, this event can be emitted from the child component as explained here in the Vue docs https://vuejs.org/guide/components/events.html#emitting-and-listening-to-events Hopefully this helps Happy Tweening! My second question about Vue here, and we're meeting again :) Thanks for your reply. I've solved this issue. I moved the timeline up one level and defined the scope so all components would be captured in it. Then, I used selectors to capture classes. So everything works fine now. I'll paste the solution here in case someone else faces this problem. I still can't figure out how to use refs with GSAP because I could have passed refs as props to these components and wouldn't have had to add classes just to querySelect() it.
Solution Rodrigo Posted October 11, 2024 Solution Posted October 11, 2024 Hi, You can use refs without any issue, like this: gsap.to(myRef.value, { ... }); The problem in your current setup is actually passing those refs from a child component to a parent one. I mentioned this before in the other thread you asked about it and I'll repeat it again, there is nothing wrong in using regular selectors as long as you are 100% sure that the DOM should look the way is intended when that code runs, that is why we recommend creating your GSAP instances inside the onMounted hook in order to avoid any issues. If you want to be even more sure you can use the nextTick method and turn the onMounted hook into an async function: onMounted(async () => { await nextTick(); // GSAP Code here! }); https://vuejs.org/api/general.html#nexttick You can use the event emitter (link in my first post in this thread) in order to create an array or object with the refs you need/want or find a way to do that, but I can guarantee you that you will be complicating things unnecessarily IMHO. Hopefully this helps Happy Tweening!
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