
在 Framer Motion 中,可通过多次调用 useScroll 并分别解构不同命名的 scrollYProgress 变量,实现对多个 ref 目标元素的独立滚动进度追踪与动画控制。
在 framer motion 中,可通过多次调用 `usescroll` 并分别解构不同命名的 `scrollyprogress` 变量,实现对多个 ref 目标元素的独立滚动进度追踪与动画控制。
Framer Motion 的 useScroll 是一个强大的钩子,用于将动画与页面滚动深度精确绑定。但其返回值(如 scrollYProgress)是单个响应式数值信号,不能被多个目标共享或复用——这正是初学者常遇到的瓶颈:当试图为多个容器(如
解决方法非常简洁而优雅:对每个 useScroll 调用进行独立声明,并使用别名解构(alias destructuring)为语义化变量名。这样每个 scrollYProgress 都绑定到专属 DOM 元素,互不干扰。
以下是完整、可运行的示例代码:
import { useRef, useState } from 'react';
import { motion, useScroll, useTransform } from 'framer-motion';
const App = () => {
const targetRef1 = useRef<HTMLDivElement>(null);
const targetRef2 = useRef<HTMLDivElement>(null);
// 独立追踪第一个目标(例如主内容区)的滚动进度
const { scrollYProgress: scrollYProgressSection1 } = useScroll({
target: targetRef1,
offset: ["start 0.2", "end 0.8"] // 元素进入视口 20% 时开始,离开前 20% 时结束
});
// 独立追踪第二个目标(例如页眉)的滚动进度
const { scrollYProgress: scrollYProgressHeader } = useScroll({
target: targetRef2,
offset: ["start 0.1", "start 0.9"] // 更早触发、更长过渡区间
});
// 基于各自进度生成动画值
const headerScale = useTransform(scrollYProgressHeader, [0, 1], [1.2, 0.8]);
const sectionOpacity = useTransform(scrollYProgressSection1, [0, 0.5, 1], [0, 1, 0.3]);
return (
<div className="App">
<motion.div
ref={targetRef2}
style={{ scale: headerScale }}
className="header"
>
<h1>Dynamic Header</h1>
</motion.div>
<div ref={targetRef1} className="main-section">
<motion.div
style={{ opacity: sectionOpacity }}
className="content"
>
<p>This section fades in and out based on its own scroll position.</p>
</motion.div>
</div>
</div>
);
};
export default App;✅ 关键要点与注意事项:
- 每个 useScroll 必须传入独立的 ref(通过 useRef() 创建),不可复用同一 ref;
- 解构时务必使用带语义的别名(如 scrollYProgressHeader),避免变量名冲突;
- offset 参数支持灵活语法(如 "start 0.1"、"end 0.2"、"center 0"),建议根据实际交互动效需求精细调整;
- 若组件中需监听大量滚动目标,建议封装自定义 Hook(如 useScrollTarget)提升可维护性;
- 注意:useScroll 仅适用于浏览器环境,在 SSR 或服务端渲染中需做安全判断(如 typeof window !== 'undefined')。
通过这种模式,你不仅能实现多目标、多节奏的滚动动画,还能为每个元素配置完全独立的触发时机、缓动曲线与变换逻辑——真正释放 Framer Motion 在复杂交互动效中的专业潜力。










