垂直全屏Swiper滚动冲突:如何禁用未滚完时的滑屏切换?
解决垂直全屏Swiper的两个核心问题
问题1:Slide内滚动与Swiper滑屏切换冲突
当slide内容溢出开启滚动后,滚动内部内容时会误触发Swiper的滑屏切换。解决逻辑是:仅当slide滚动到顶部/底部边缘时,才允许Swiper触发滑屏切换。
实现步骤:
- 给Swiper组件添加
ref,用于获取实例进行状态控制 - 给可滚动的slide绑定滚动事件,实时判断滚动位置
- 根据滚动位置动态启用/禁用Swiper的鼠标滚轮和触摸滑动功能
修改后的MainSlider.js代码:
import { useEffect, useRef } from 'react'; import { Swiper, SwiperSlide } from 'swiper/react'; import 'swiper/css'; import 'swiper/css/pagination'; import { Mousewheel, Pagination } from 'swiper/modules'; const MainSlider = () => { const swiperRef = useRef(null); const slideRefs = useRef([]); // 处理slide滚动事件 const handleSlideScroll = (e) => { const slide = e.target; const isAtTop = slide.scrollTop === 0; const isAtBottom = slide.scrollTop + slide.clientHeight >= slide.scrollHeight; const swiper = swiperRef.current?.swiper; if (swiper) { // 只有滚动到边缘时,才允许Swiper的滑屏和滚轮控制 swiper.mousewheel.enable(isAtTop || isAtBottom); swiper.touchEventsEnabled = isAtTop || isAtBottom; } }; useEffect(() => { // 给所有可滚动的slide绑定滚动事件 slideRefs.current.forEach(ref => { if (ref) { ref.addEventListener('scroll', handleSlideScroll); } }); return () => { // 清理事件监听 slideRefs.current.forEach(ref => { if (ref) { ref.removeEventListener('scroll', handleSlideScroll); } }); }; }, []); return ( <Swiper ref={swiperRef} className={styles.swiper} direction="vertical" slidesPerView="auto" spaceBetween={0} mousewheel={true} speed={700} touchReleaseOnEdges={true} threshold={20} pagination={{ clickable: true, }} modules={[Mousewheel, Pagination]} > <SwiperSlide className={styles.slide} ref={el => slideRefs.current[0] = el}> <SectionOne/> </SwiperSlide> <SwiperSlide className={styles.slide} ref={el => slideRefs.current[1] = el}> <AnswersTwo/> </SwiperSlide> </Swiper> ); }; export default MainSlider;
问题2:移动端模式切换后滑屏功能需刷新才生效
窗口尺寸切换到移动端模式时,Swiper没有自动更新布局和状态,导致滑屏功能失效。解决逻辑是:监听窗口resize事件,触发Swiper实例的update方法,同时重新调整滚动控制逻辑。
实现步骤:
在原有的useEffect中添加resize事件监听,更新Swiper实例并重置滚动状态:
修改MainSlider.js中的useEffect:
useEffect(() => { // 绑定slide滚动事件 const bindScrollEvents = () => { slideRefs.current.forEach(ref => { if (ref) { ref.removeEventListener('scroll', handleSlideScroll); ref.addEventListener('scroll', handleSlideScroll); // 初始化时判断一次滚动位置 handleSlideScroll({ target: ref }); } }); }; bindScrollEvents(); // 监听窗口resize事件 const handleResize = () => { const swiper = swiperRef.current?.swiper; if (swiper) { swiper.update(); // 更新Swiper布局 bindScrollEvents(); // 重新绑定滚动事件并初始化状态 } }; window.addEventListener('resize', handleResize); return () => { window.removeEventListener('resize', handleResize); slideRefs.current.forEach(ref => { if (ref) { ref.removeEventListener('scroll', handleSlideScroll); } }); }; }, []);
同时优化SCSS中的滚动样式,避免干扰:
.swiper { width: 100%; height: 100vh; } .slide { min-height: 100vh; text-align: center; font-size: 18px; background: #fff; display: flex; justify-content: center; align-items: center; margin: auto; overflow: hidden; @media only screen and (max-width: 1023px) { flex-wrap: wrap; overflow-y: scroll; // 明确垂直滚动,避免横向滚动干扰 -webkit-overflow-scrolling: touch; // 优化移动端滚动手感 } }
内容的提问来源于stack exchange,提问作者wannnwdooo
相关产品推荐
相关产品推荐

