如何实现滑块按20vw步进滚动?解决快速滚动失效问题
问题:滑块滚动时仅按20vw步进,快速滚动异常修复
我希望滑块在滚动时每次移动20vw,慢速滚动时功能正常,但快速滚动会出现异常。尝试过防抖函数和evt.preventDefault(),都没解决问题。请问如何实现滑块仅按20vw步进滚动?
<div class="slider-container" id="slider-container"> <div class="slider" id="slider"> <img src="https://www.referenseo.com/wp-content/uploads/2019/03/image-attractive-960x540.jpg" class="slider-image" id="slider-image"> <img src="https://plus.unsplash.com/premium_photo-1664474619075-644dd191935f?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8MXx8aW1hZ2V8ZW58MHx8MHx8fDA%3D&w=1000&q=80" class="slider-image" id="slider-image"> <img src="https://99designs-blog.imgix.net/blog/wp-content/uploads/2016/03/web-images.jpg?auto=format&q=60&w=1600&h=824&fit=crop&crop=faces" class="slider-image" id="slider-image"> <img src="https://cdn.futura-sciences.com/sources/images/dossier/773/01-intro-773.jpg" class="slider-image" id="slider-image"> <img src="https://imgv3.fotor.com/images/blog-cover-image/part-blurry-image.jpg" class="slider-image" id="slider-image"> <img src="https://images.ctfassets.net/hrltx12pl8hq/3j5RylRv1ZdswxcBaMi0y7/b84fa97296bd2350db6ea194c0dce7db/Music_Icon.jpg" class="slider-image" id="slider-image"> <img src="https://h5p.org/sites/default/files/h5p/content/1209180/images/file-6113d5f8845dc.jpeg" class="slider-image" id="slider-image"> <img src="https://www.referenseo.com/wp-content/uploads/2019/03/image-attractive-960x540.jpg" class="slider-image" id="slider-image"> <img src="https://www.referenseo.com/wp-content/uploads/2019/03/image-attractive-960x540.jpg" class="slider-image" id="slider-image"> <img src="https://www.referenseo.com/wp-content/uploads/2019/03/image-attractive-960x540.jpg" class="slider-image" id="slider-image"> <img src="https://www.referenseo.com/wp-content/uploads/2019/03/image-attractive-960x540.jpg" class="slider-image" id="slider-image"> <img src="https://www.referenseo.com/wp-content/uploads/2019/03/image-attractive-960x540.jpg" class="slider-image" id="slider-image"> <div class="button-container"> <button class="prev">Prev</button> <button class="next">Next</button> </div> </div> </div>
* { margin: 0px; padding: 0px; box-sizing: border-box; font-size: 1rem; } .slider-page { height: 80vh; width: 100vw; position: absolute; } .slider-container { height: 100%; width: 100%; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); display: flex; align-items: center; justify-content: center; } .slider { display: flex; width: 100%; position: relative; top: 0px; left: 0px; overflow: hidden; overflow-y: scroll; scroll-behavior: smooth; } .slider-image { width: 20vw; padding: 20px; border-radius: 40px; object-fit: cover; transition: transform 0.3s ease-in-out, opacity 0.3s ease-in-out; @media (max-width: 768px) { width: 33vw; padding: 20px; } } .slide-transition { transition: transform 0.3s ease-in-out, opacity 0.3s ease-in-out; } .button-container { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); display: flex; justify-content: space-between; width: 20vw; } .next, .prev { padding: 10px; border-radius: 10px; }
const slider = document.getElementById("slider"); const slides = document.querySelectorAll(".slider-image"); const sliderPage = document.getElementById("slider-page"); // Slide size logic function updateSlides() { let smallWidth = window.innerWidth / 6; let mediumWidth = window.innerWidth / 3; let fullWidth = window.innerWidth / 2; slides.forEach((slide) => { let imagePosition = slide.getBoundingClientRect().x; if ( (imagePosition >= smallWidth && imagePosition < mediumWidth) || (imagePosition > fullWidth && imagePosition <= 5 * smallWidth) ) { slide.style.transform = "scale(0.6)"; slide.style.opacity = "0.6"; } else if (imagePosition >= mediumWidth && imagePosition <= fullWidth) { slide.style.transform = "scale(1)"; slide.style.opacity = "1"; } else { slide.style.transform = "scale(0.3)"; slide.style.opacity = "0.3"; } }); } // Button sliding logic let slidercontainer = document.getElementById("slider-container"); let nextbutton = document.querySelector(".next"); let prevbutton = document.querySelector(".prev"); let scrollAmountVW = 20; nextbutton.onclick = () => { slider.scrollLeft += (scrollAmountVW * window.innerWidth) / 100; updateSlides(); }; prevbutton.onclick = () => { slider.scrollLeft -= (scrollAmountVW * window.innerWidth) / 100; updateSlides(); }; slider.addEventListener("scroll", () => { updateSlides(); }); slider.addEventListener("wheel", (evt) => { evt.preventDefault(); const scrollDirection = evt.deltaY > 0 ? 1 : -1; slider.scrollLeft += (scrollAmountVW * scrollDirection * window.innerWidth) / 100; updateSlides(); }); // Script launch order document.addEventListener("DOMContentLoaded", function() { updateSlides(); window.addEventListener("resize", () => { updateSlides(); }); window.addEventListener("scroll", () => { updateSlides(); }); });
(请全屏运行代码片段查看预期效果)
解决方案:用节流控制滚动触发频率
快速滚动异常的核心原因是:鼠标滚轮事件会在短时间内连续触发多次,即便调用了preventDefault,每次事件仍会执行scrollLeft累加,导致一次滚动触发多次步进。用节流函数限制事件触发频率,就能确保指定时间内只执行一次滚动操作。
修改后的JavaScript代码
const slider = document.getElementById("slider"); const slides = document.querySelectorAll(".slider-image"); // Slide size logic function updateSlides() { let smallWidth = window.innerWidth / 6; let mediumWidth = window.innerWidth / 3; let fullWidth = window.innerWidth / 2; slides.forEach((slide) => { let imagePosition = slide.getBoundingClientRect().x; if ( (imagePosition >= smallWidth && imagePosition < mediumWidth) || (imagePosition > fullWidth && imagePosition <= 5 * smallWidth) ) { slide.style.transform = "scale(0.6)"; slide.style.opacity = "0.6"; } else if (imagePosition >= mediumWidth && imagePosition <= fullWidth) { slide.style.transform = "scale(1)"; slide.style.opacity = "1"; } else { slide.style.transform = "scale(0.3)"; slide.style.opacity = "0.3"; } }); } // Button sliding logic let nextbutton = document.querySelector(".next"); let prevbutton = document.querySelector(".prev"); let scrollAmountVW = 20; nextbutton.onclick = () => { slider.scrollLeft += (scrollAmountVW * window.innerWidth) / 100; updateSlides(); }; prevbutton.onclick = () => { slider.scrollLeft -= (scrollAmountVW * window.innerWidth) / 100; updateSlides(); }; slider.addEventListener("scroll", () => { updateSlides(); }); // 节流函数:限制事件触发频率 function throttle(func, delay) { let lastCall = 0; return function(...args) { const now = Date.now(); if (now - lastCall >= delay) { lastCall = now; return func(...args); } }; } // 用节流包装滚轮事件处理函数 const handleWheel = throttle((evt) => { evt.preventDefault(); const scrollDirection = evt.deltaY > 0 ? 1 : -1; slider.scrollLeft += (scrollAmountVW * scrollDirection * window.innerWidth) / 100; updateSlides(); }, 300); // 300ms间隔,可根据需求调整 slider.addEventListener("wheel", handleWheel); // Script launch order document.addEventListener("DOMContentLoaded", function() { updateSlides(); window.addEventListener("resize", updateSlides); });
关键修改点
- 新增
throttle节流函数,限制滚轮事件在300ms内仅执行一次,避免快速滚动时连续触发多次步进 - 将滚轮事件处理函数用节流包装,确保每次滚动只触发一次20vw的位移
- 移除不必要的
window.addEventListener("scroll", updateSlides),滑块内部的scroll事件已足够触发样式更新
额外优化
修改.slider的CSS样式,隐藏垂直滚动条避免干扰操作:
.slider { display: flex; width: 100%; position: relative; top: 0px; left: 0px; overflow: hidden; overflow-x: auto; /* 仅保留水平滚动 */ scroll-behavior: smooth; }
内容的提问来源于stack exchange,提问作者Bamboozles83278
相关产品推荐
相关产品推荐

