React横向滚动站点实现垂直滚动转横向并兼容scroll-behavior:smooth咨询
问题根源
你原始代码的异常表现来自三个核心问题:
- 未阻止滚轮默认行为:浏览器默认的纵向滚动逻辑和你手动修改
scrollLeft的逻辑冲突,导致滚动距离被抵消,速度异常变慢 - 未区分滚动方向:当用户触发横向滚动(触控板横向滑动、带横向滚轮的鼠标)时,你额外叠加的
scrollLeft修改会和原生横向滚动逻辑冲突,造成卡顿 - 和
scroll-behavior: smooth的冲突:全局CSS设置该属性后,每一次scrollLeft赋值都会触发平滑过渡动画,多次连续赋值会出现动画队列挤压,导致滚动滞后、速度异常、卡顿
完整实现方案
基础滚动转换逻辑(React适配版)
直接在React组件内实现,避免原生全局监听的内存泄漏问题,核心逻辑自动区分横竖滚动,适配不同设备的滚轮参数:
import { useRef, useEffect } from 'react'; const PortfolioGallery = () => { const scrollerRef = useRef(null); useEffect(() => { const scroller = scrollerRef.current; if (!scroller) return; const handleWheel = (e) => { // 原生横向滚动直接交给系统处理,不做额外逻辑 if (Math.abs(e.deltaX) > Math.abs(e.deltaY)) return; // 阻止默认纵向滚动行为,避免冲突 e.preventDefault(); // 自定义滚动速度系数,可根据实际体验调整 const speedCoefficient = 1.5; const scrollIncrement = e.deltaY * speedCoefficient; // 用scrollTo方法控制滚动,不直接修改scrollLeft scroller.scrollTo({ left: scroller.scrollLeft + scrollIncrement, // 滚轮滚动时关闭平滑动画,避免卡顿 behavior: 'auto' }); }; scroller.addEventListener('wheel', handleWheel, { passive: false }); return () => scroller.removeEventListener('wheel', handleWheel); }, []); // 按钮平滑跳转的示例方法 const scrollToSection = (position) => { scrollerRef.current?.scrollTo({ left: position, // 主动触发跳转时开启平滑动画 behavior: 'smooth' }); }; return ( <div ref={scrollerRef} style={{ overflowX: 'scroll', overflowY: 'hidden', msOverflowStyle: 'none', scrollbarWidth: 'none', // 不要全局设置scroll-behavior: smooth,改为JS按需控制 }} > {/* 画廊内容 */} <button onClick={() => scrollToSection(1000)}>跳转到指定位置</button> </div> ); };
圆形滚动适配
要实现圆形滚动的正弦曲线效果,直接取用滚轮事件的deltaX和deltaY做组合计算即可,修改handleWheel里的滚动增量计算逻辑:
const handleWheel = (e) => { e.preventDefault(); const speedCoefficient = 1.5; // 组合横竖方向的滚动值,按你需要的正弦规则调整计算逻辑即可 const scrollIncrement = (e.deltaY + Math.sin(e.deltaX / 100) * 100) * speedCoefficient; scroller.scrollTo({ left: scroller.scrollLeft + scrollIncrement, behavior: 'auto' }); };
平滑滚动共存说明
不需要全局设置CSS的scroll-behavior: smooth,改为在JS触发滚动时按需指定behavior参数即可:
- 滚轮触发的滚动转换:指定
behavior: 'auto',避免动画冲突导致的卡顿 - 按钮点击、锚点跳转等主动触发的滚动:指定
behavior: 'smooth',保留平滑过渡效果
两种场景互不影响,完全覆盖你的需求。
内容的提问来源于stack exchange,提问作者JJgendarme
相关产品推荐
相关产品推荐

