React实现双组件垂直与水平同步滚动效果
React实现垂直滚动同步驱动水平组件滚动方案
实现效果参考:
实现逻辑
放弃原有transform旋转90度的实现思路(该方案易出现定位偏移、滚动条异常、移动端适配差的问题),直接监听页面垂直滚动事件,将垂直滚动的进度按比例映射为水平固定容器的横向滚动偏移,逻辑可控、调试成本低。
核心逻辑点:
- 紫色长页面保留正常文档流,撑出页面垂直滚动高度
- 蓝、绿色所在的水平滚动容器设置为fixed定位,固定在视口指定位置,隐藏自身滚动条
- 监听window的scroll事件,计算当前垂直滚动进度,同步设置水平容器的scrollLeft值
- 用requestAnimationFrame做滚动回调节流,保证滚动流畅不卡顿
修正后代码
样式代码(horzantalComponent.css)
* { margin: 0; padding: 0; box-sizing: border-box; } .page{ height: 300vh; background-color: purple; position: relative; z-index: 1; } .horizantalContainer{ position: fixed; /* 水平容器默认固定在视口垂直居中位置,可自行修改top/bottom调整位置 */ top: 50%; left: 0; transform: translateY(-50%); width: 100vw; height: 35vh; overflow: hidden; background-color: blue; z-index: 10; } .wrapper{ display: flex; height: 100%; width: 300vw; } .slide{ height: 100%; width: 100vw; display: flex; align-items: center; padding: 2rem; } .slide:nth-child(1){ background-color: lightblue; justify-content: flex-end; } .slide:nth-child(2){ background-color: lightgreen; } .slide:nth-child(3){ background-color: lightpink; }
组件代码
import React, { useEffect, useRef } from 'react' import "./horzantalComponent.css" const HorzantalComponent = () => { const scrollContainerRef = useRef(null) const wrapperRef = useRef(null) useEffect(() => { const container = scrollContainerRef.current const wrapper = wrapperRef.current if (!container || !wrapper) return // 水平方向最大可滚动距离 const maxHorizontalScroll = wrapper.scrollWidth - container.clientWidth // 垂直方向需要滚动的总行程:值越小水平滚动越快,值越大水平滚动越慢 const verticalScrollRange = window.innerHeight * 2 let ticking = false const handleScroll = () => { if (!ticking) { window.requestAnimationFrame(() => { const scrollY = window.scrollY // 计算滚动进度,限制在0-1区间避免越界 const scrollProgress = Math.min(Math.max(scrollY / verticalScrollRange, 0), 1) // 同步水平滚动位置 container.scrollLeft = scrollProgress * maxHorizontalScroll ticking = false }) ticking = true } } // 绑定事件,passive配置提升滚动性能 window.addEventListener('scroll', handleScroll, { passive: true }) window.addEventListener('resize', handleScroll) // 初始化校准位置 handleScroll() return () => { window.removeEventListener('scroll', handleScroll) window.removeEventListener('resize', handleScroll) } }, []) return ( <div> <div className="page"> <div className='horizantalContainer' ref={scrollContainerRef}> <div className='wrapper' ref={wrapperRef}> <div className='slide'> <p>Horizantal Slide component slide</p> </div> <div className='slide'> </div> <div className='slide'></div> </div> </div> </div> </div> ) } export default HorzantalComponent
可调参数说明
- 调整水平组件固定位置:修改
.horizantalContainer的定位属性,比如固定在顶部可设top: 0; transform: none;,固定在底部可设bottom: 0; transform: none; - 调整水平滚动速度:修改
verticalScrollRange的取值,比如改为window.innerHeight * 3代表需要滚动3倍视口高度才能走完水平内容全程,滚动速度会变慢 - 调整水平内容总宽度:修改
.wrapper的width值,同步增减slide数量即可,代码会自动计算最大滚动距离,不需要手动改逻辑
内容的提问来源于stack exchange,提问作者tabba
相关产品推荐
相关产品推荐


