Nuxt项目中Lenis与ScrollTrigger结合动画失效问题求助
解决Nuxt中GSAP ScrollTrigger无动画问题
问题诊断
代码能触发onEnter回调,说明ScrollTrigger的触发逻辑正常,但动画未执行,核心问题是动画属性被错误嵌套在scrollTrigger配置内,同时需要处理Lenis自定义滚动与ScrollTrigger的兼容性。
修复步骤
1. 修正GSAP动画配置结构
把y、ease这类动画属性从scrollTrigger对象中移到gsap.to的根配置层级,scrollTrigger仅负责滚动触发条件:
mounted() { gsap.registerPlugin(ScrollTrigger); const trigger = this.$refs.animtrigger; console.log(trigger); gsap.to(trigger, { // 动画属性放在根层级 y: '-=100px', ease: "power1.inOut", scrollTrigger: { trigger: trigger, start: 'top center', onEnter: () => { console.log('coucou') } } }) }
注:
stagger是多元素序列动画的延迟参数,单个元素使用不会生效,若要给子元素做序列动画,需将目标改为trigger.querySelectorAll('.column > *')这类选择器。
2. 兼容Lenis自定义滚动
Lenis会接管原生滚动,需要让ScrollTrigger监听Lenis的滚动事件,添加以下配置:
// 在mounted注册插件后添加 ScrollTrigger.scrollerProxy(document.body, { scrollTop(value) { return window.lenis ? window.lenis.scroll : value; }, getBoundingClientRect() { return { top: 0, left: 0, width: window.innerWidth, height: window.innerHeight }; }, pinType: document.querySelector(".projectItem").style.transform ? "transform" : "fixed" }); // 绑定Lenis滚动事件更新ScrollTrigger window.lenis.on('scroll', ScrollTrigger.update);
3. 优化插件注册(可选)
在Nuxt中创建全局插件plugins/gsap.client.js,避免组件重复注册:
import { gsap } from 'gsap'; import ScrollTrigger from 'gsap/ScrollTrigger'; export default defineNuxtPlugin(() => { gsap.registerPlugin(ScrollTrigger); return { provide: { gsap, ScrollTrigger } }; });
组件内可通过const { gsap } = useNuxtApp();直接使用,无需重复导入。
4. 设置元素初始状态
若动画是向上位移,给元素初始添加位移/隐藏样式,让动画效果更明显:
.projectItem { width: 628px; transform: translateY(100px); // 初始向下偏移 opacity: 0; // 初始隐藏 transition: none; // 禁用CSS过渡,避免和GSAP冲突 // 其他样式... }
动画中对应修改为回到初始位置并显示:
gsap.to(trigger, { y: 0, opacity: 1, ease: "power1.inOut", scrollTrigger: { trigger: trigger, start: 'top center' } })
完整修正后的组件代码
<script> import { gsap } from "gsap"; import ScrollTrigger from 'gsap/ScrollTrigger'; export default { mounted() { gsap.registerPlugin(ScrollTrigger); const trigger = this.$refs.animtrigger; // 兼容Lenis滚动 ScrollTrigger.scrollerProxy(document.body, { scrollTop(value) { return window.lenis ? window.lenis.scroll : value; }, getBoundingClientRect() { return { top: 0, left: 0, width: window.innerWidth, height: window.innerHeight }; }, pinType: trigger.style.transform ? "transform" : "fixed" }); window.lenis.on('scroll', ScrollTrigger.update); // 修正动画配置 gsap.to(trigger, { y: 0, opacity: 1, ease: "power1.inOut", scrollTrigger: { trigger: trigger, start: 'top center', onEnter: () => { console.log('coucou') } } }) }, props: { titre: String, type: String, composition: Array, outils: Array, date: String, image: String, alt: String } } </script> <template> <div class="projectItem" ref="animtrigger"> <div class="column"> <div class="column-c-image"> <img :src="image" :alt="alt" class="image"> </div> <div class="column-c-content"> <p>{{titre}}</p> <svg class="arrow" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M6.22438 17.9287C6.36591 18.0667 6.55676 18.1423 6.75438 18.1387C6.95141 18.1391 7.14109 18.064 7.28438 17.9287L16.6144 8.58994V16.6487C16.6144 17.0629 16.9502 17.3987 17.3644 17.3987C17.5658 17.4042 17.7608 17.3273 17.9042 17.1857C18.0477 17.0442 18.1272 16.8502 18.1244 16.6487V6.9165C18.1504 6.80241 18.1498 6.68188 18.1198 6.56444C18.0519 6.29871 17.8444 6.09121 17.5787 6.02334C17.4612 5.99335 17.3407 5.99275 17.2266 6.01873H7.49438C7.08017 6.01873 6.74438 6.35451 6.74438 6.76873C6.74438 7.18294 7.08017 7.51873 7.49438 7.51873H15.5644L6.22438 16.8587C6.08085 16.9997 6 17.1925 6 17.3937C6 17.5949 6.08085 17.7877 6.22438 17.9287Z" fill="black"/> </svg> </div> </div> </div> </template> <style scoped lang="scss"> @use "~/assets/css/main.scss"; .projectItem { width: 628px; transform: translateY(100px); opacity: 0; transition: none; .column { display: flex; flex-direction: column; gap: .2rem; .column-c-image { object-fit: cover; .image { width: 100%; height: 700px; object-fit: cover; border-radius: 1rem; } } .column-c-content { display: flex; flex-direction: row; justify-content: space-between; align-items: center; width: 100%; } } } </style>
内容的提问来源于stack exchange,提问作者Maël Ar
相关产品推荐
相关产品推荐

