如何实现滚动到滑块区域时停止滚动优先切换幻灯片的效果
实现方案
HTML 代码
<section></section> <section></section> <section></section> <!-- 滑块区域外层占位,避免fixed后页面高度塌陷 --> <div class="slider-wrapper"> <section class="slider"> <div class="slide active">Slide 1</div> <div class="slide">Slide 2</div> <div class="slide">Slide 3</div> </section> </div> <section></section> <section></section>
CSS 代码
* { margin: 0; padding: 0; box-sizing: border-box; } section { width: 100%; height: 500px; } section:nth-child(odd) { background-color: #666; } /* 滑块外层占位容器,高度和滑块一致,避免fixed后页面跳变 */ .slider-wrapper { height: 500px; } section.slider { background-color: #e03c0b; display: flex; justify-content: center; align-items: center; } .slide { display: none; text-align: center; width: 50%; height: 200px; background-color: #888; } .slide.active { display: block; } .fixed { position: fixed; top: 0; left: 0; width: 100%; }
JS 代码
const container = document.querySelector('.slider'); const slides = document.querySelectorAll('.slide'); const slideCount = slides.length; // 记录当前展示的幻灯片索引 let currentSlideIndex = 0; // 记录滑块是否处于固定状态 let isSliderFixed = false; // 切换幻灯片的公共方法 function switchSlide(index) { slides.forEach(el => el.classList.remove('active')); slides[index].classList.add('active'); currentSlideIndex = index; } // 监听页面滚动,判断是否需要固定滑块 window.addEventListener('scroll', () => { const scrollTop = window.pageYOffset; const sliderOffsetTop = document.querySelector('.slider-wrapper').offsetTop; // 滚动到滑块区域,且还未完成所有幻灯片切换时,固定滑块 if (scrollTop >= sliderOffsetTop && currentSlideIndex < slideCount - 1 && !isSliderFixed) { container.classList.add('fixed'); isSliderFixed = true; } // 滚动回滑块区域上方时,重置幻灯片索引 if (scrollTop < sliderOffsetTop && currentSlideIndex !== 0) { switchSlide(0); if (isSliderFixed) { container.classList.remove('fixed'); isSliderFixed = false; } } }) // 核心:监听滚轮事件,控制滚动优先级 window.addEventListener('wheel', (e) => { // 只有滑块固定时才拦截滚动 if (!isSliderFixed) return; // 向下滚动 if (e.deltaY > 0) { e.preventDefault(); // 还有下一张幻灯片,切换 if (currentSlideIndex < slideCount - 1) { switchSlide(currentSlideIndex + 1); } // 已经是最后一张,解除固定,恢复页面滚动 else { container.classList.remove('fixed'); isSliderFixed = false; // 直接滚动到滑块下方区域,避免跳变 window.scrollTo(0, document.querySelector('.slider-wrapper').offsetTop + container.offsetHeight); } } // 向上滚动 else if (e.deltaY < 0) { e.preventDefault(); // 还有上一张幻灯片,切换 if (currentSlideIndex > 0) { switchSlide(currentSlideIndex - 1); } // 已经是第一张,解除固定,恢复页面滚动 else { container.classList.remove('fixed'); isSliderFixed = false; // 直接滚动到滑块上方区域,避免跳变 window.scrollTo(0, document.querySelector('.slider-wrapper').offsetTop - 1); } } // 必须设置passive: false,否则preventDefault会被浏览器忽略报错 }, { passive: false })
关键逻辑说明
- 新增
.slider-wrapper占位容器,解决滑块fixed后脱离文档流导致的页面高度突变、内容跳闪问题 - 监听
wheel事件时主动设置passive: false,确保可以正常调用e.preventDefault()拦截原生滚动 - 仅在滑块处于固定状态时拦截滚动事件,其他时间保留原生滚动体验
- 边界状态自动解除固定:向下滚动到最后一张幻灯片、向上滚动到第一张幻灯片时,自动退出固定状态,同时调用
window.scrollTo定位到对应位置,避免滚动断层
内容的提问来源于stack exchange,提问作者Gremlin
相关产品推荐
相关产品推荐

