如何在ReactJS与Framer Motion中实现Y轴滚动联动X轴滚动
React + Framer Motion实现滚动联动:Y轴滚动触发X轴横向滚动
核心思路
监听页面垂直滚动进度,将该进度映射为目标横向容器的水平偏移量,借助Framer Motion的useScroll和useTransform钩子实现平滑的滚动联动,复刻目标板块的交互效果。
实现步骤与代码示例
1. 基础组件结构
先搭建页面框架:一个提供垂直滚动空间的父容器,内部包含横向排列的项目列表容器。
import { motion, useScroll, useTransform } from "framer-motion"; import { useRef, useEffect, useState } from "react"; import "./OurWork.css"; const OurWork = () => { // 滚动联动逻辑将在此添加 return ( <section className="our-work-container"> <motion.div className="horizontal-scroll-content" ref={contentRef} style={{ x: scrollXOffset }} > {[1,2,3,4,5,6,7].map((item) => ( <div key={item} className="work-card"> <div className="card-content">Project {item}</div> </div> ))} </motion.div> </section> ); }; export default OurWork;
2. 添加滚动联动逻辑
用Framer Motion的钩子把垂直滚动进度转换成横向容器的X轴偏移:
const OurWork = () => { const contentRef = useRef(null); const [maxOffset, setMaxOffset] = useState(0); // 获取整个页面的垂直滚动进度 const { scrollYProgress } = useScroll({ target: document.documentElement, offset: ["start start", "end end"] }); // 计算横向内容的最大滚动偏移量(内容总宽度 - 容器可视宽度) useEffect(() => { const updateMaxOffset = () => { if (contentRef.current) { const { scrollWidth, clientWidth } = contentRef.current; setMaxOffset(scrollWidth - clientWidth); } }; updateMaxOffset(); // 监听窗口 resize,动态更新偏移量 window.addEventListener("resize", updateMaxOffset); return () => window.removeEventListener("resize", updateMaxOffset); }, []); // 将0-1的滚动进度映射为X轴偏移值:0对应0,1对应-maxOffset const scrollXOffset = useTransform(scrollYProgress, [0, 1], [0, -maxOffset]); return ( <section className="our-work-container"> <motion.div className="horizontal-scroll-content" ref={contentRef} style={{ x: scrollXOffset }} > {[1,2,3,4,5,6,7].map((item) => ( <div key={item} className="work-card"> <div className="card-content">Project {item}</div> </div> ))} </motion.div> </section> ); };
3. 关键样式配置(OurWork.css)
确保横向容器正常排列,父容器提供足够垂直滚动空间:
.our-work-container { min-height: 200vh; /* 让页面有足够垂直滚动区域 */ display: flex; align-items: center; overflow: hidden; padding: 4rem 0; } .horizontal-scroll-content { display: flex; gap: 2rem; padding: 0 1rem; /* 隐藏原生横向滚动条 */ scrollbar-width: none; } .horizontal-scroll-content::-webkit-scrollbar { display: none; } .work-card { width: 350px; height: 450px; flex-shrink: 0; background-color: #f0f0f0; border-radius: 8px; display: flex; align-items: center; justify-content: center; font-size: 1.2rem; font-weight: 500; }
关键细节说明
useScroll的offset参数:["start start", "end end"]定义滚动进度的起止点——当页面顶部与视口顶部对齐时进度为0,页面底部与视口底部对齐时进度为1,确保联动范围覆盖整个垂直滚动过程。- 动态偏移量计算:通过监听窗口resize事件,实时更新横向内容的最大偏移量,适配不同屏幕尺寸。
- 平滑动画:Framer Motion的
useTransform会自动处理偏移值的过渡动画,无需额外添加缓动逻辑。
内容的提问来源于stack exchange,提问作者DeadMan
相关产品推荐
相关产品推荐

