如何在每次窗口resize时更新GSAP matchMedia内的动画变量
问题根因
你的推测完全准确:ScrollTrigger.matchMedia() 仅在媒体查询断点切换时触发逻辑重跑——也就是宽度从699px升到700px及以上、或是从700px以上降到699px及以下的瞬间,才会销毁上一个断点的动画实例,执行当前断点的初始化代码。同一断点区间内的窗口resize,不会自动重跑回调。
自行添加resize监听未生效的核心原因有两点:
containerWidth、containerHeight是matchMedia回调内的局部变量,动画初始化时,x: containerWidth/2、y: containerHeight/2这类写法已经把当时计算出的固定数值写入了动画配置,后续就算修改变量值,已经生成的动画实例不会自动读取更新后的变量- 没有触发ScrollTrigger的重算流程,动画参数、滚动触发位置始终沿用初始化时的旧值
可行实现方案
方案1:动画属性传入动态计算函数(推荐,性能最优)
GSAP原生支持动画属性值传入函数,每次动画渲染时都会自动执行函数取最新值,不需要额外绑定resize事件,也不需要手动触发刷新,代码修改量最小:
ScrollTrigger.matchMedia({ "(min-width: 700px)": function () { const seeThroughEle = document.querySelector(".see-through"); const tl = gsap.timeline({ scrollTrigger: { // 保留原有ScrollTrigger配置 } }); tl.to(".logo-transparent", { // 传入函数实时计算宽度,每次渲染取最新值 x: () => parseInt(getComputedStyle(seeThroughEle).width) / 2, scale: "0.8" }); }, "(max-width: 699px)": function () { const seeThroughEle = document.querySelector(".see-through"); const tl = gsap.timeline({ scrollTrigger: { // 保留原有ScrollTrigger配置 } }); tl.to(".logo-transparent", { // 传入函数实时计算高度 y: () => parseInt(getComputedStyle(seeThroughEle).height) / 2, scale: "0.9" }) } });
这个方案没有额外的事件监听开销,窗口尺寸任意变化时动画都会自动读取最新的容器尺寸,适配绝大多数场景。
方案2:防抖resize后强制刷新ScrollTrigger(适合复杂动画场景)
如果动画逻辑复杂,存在大量依赖尺寸的联动计算,不方便全部改成函数传值的形式,可以给window绑定加了防抖的resize事件,每次窗口尺寸调整结束后,调用ScrollTrigger的官方刷新方法,强制重算所有动画参数和滚动触发位置:
let resizeDebounceTimer = null; window.addEventListener('resize', () => { clearTimeout(resizeDebounceTimer); // 窗口停止调整150ms后再触发刷新,避免频繁计算掉帧 resizeDebounceTimer = setTimeout(() => { ScrollTrigger.refresh(); }, 150); });
注意这个方法会遍历重算页面上所有的ScrollTrigger实例,如果页面动画量级较大,一定要做好防抖控制触发频率,避免性能问题。
内容的提问来源于stack exchange,提问作者Praneet Dixit
相关产品推荐
相关产品推荐

