在Vue/Nuxt中通过Pinia共享GSAP主时间线异常问题
Nuxt3 + Pinia + GSAP 主时间线无法播放子时间线问题解决
问题核心原因
GSAP时间线是带有内部状态的复杂实例,直接将其存入Pinia的state时,Vue的响应式系统会自动包装该实例,这会干扰GSAP内部的动画调度逻辑,导致主时间线无法触发更新、完成回调,子时间线也无法正常运行。
解决步骤
- 用
markRaw标记GSAP时间线,跳过响应式包装
在你的Pinia store文件(stores/AnimationStore.ts)中,初始化主时间线时使用Vue的markRaw方法,避免Vue对GSAP实例做响应式处理:
import { defineStore } from 'pinia' import gsap from 'gsap' import { markRaw } from 'vue' export const useAnimationStore = defineStore('animation', { state: () => ({ // 用markRaw包装GSAP时间线,规避响应式干扰 master: markRaw(gsap.timeline({ onStart: () => console.log('Master started'), onUpdate: () => console.log('Master updated'), onComplete: () => console.log('Master completed') })) }), actions: { addToMaster(timeline: gsap.core.Timeline) { this.master.add(timeline) }, playMaster() { this.master.play() } } })
- 确保子时间线在DOM挂载后创建
Nuxt3组件的DOM元素需在onMounted钩子后才会完全挂载到页面,若在组件初始化阶段创建子时间线,可能因目标元素不存在导致动画无效。调整app.vue代码,在onMounted中创建并添加子时间线:
<script setup> import { useAnimationStore } from '~/stores/AnimationStore' import gsap from 'gsap' import { onMounted } from 'vue' const animationStore = useAnimationStore() onMounted(() => { // 确认DOM元素存在后创建子时间线 const subTimeline = gsap.timeline() // 示例动画:移动id为box的元素 subTimeline.to('#box', { x: 200, duration: 1 }) animationStore.addToMaster(subTimeline) animationStore.playMaster() }) </script> <template> <!-- 添加动画目标元素 --> <div id="box" style="width: 100px; height: 100px; background-color: red;"></div> </template>
- 检查时间线配置
确认主时间线初始化时无paused: true以外的异常配置,子时间线未被手动暂停、无无效动画目标。
验证效果
完成上述调整后,播放主时间线时应正常触发onUpdate和onComplete日志,子时间线的动画也会正常执行。
内容的提问来源于stack exchange,提问作者Lutz
相关产品推荐
相关产品推荐

