Вот мой взгляд на вашу проблему: мы можем использовать window.requestAnimationFrame
, чтобы выполнить прокрутку для вас. Причина, по которой я выбираю не использовать window.setTimeout()
или window.setInterval()
, заключается в том, что он не очень надежен (подвержен дрейфу), поскольку выполнение его обратных вызовов выдвигается до конца стека вызовов. window.requestAnimationFrame
будет прокручивать ваш элемент, как только браузер сможет снова перерисовать, что оптимизирует производительность.
Затем вы можете прервать рекурсивный вызов window.requestAnimationFrame
при обнаружении определенного события (например, mousewheel
или touchend
), а затем установите тайм-аут для возобновления прокрутки.
См. пример проверки концепции ниже:
const scrollSpeedPerSecond = 150;
const scroller = document.getElementById('wrapper');
const timeToWaitBeforeResumeScrolling = 1000;
let previousTimestamp;
let allowScroll = true;
function scrollStep() {
if (!previousTimestamp)
previousTimestamp = new Date().getTime();
const currentTimestamp = new Date().getTime();
const elapsedTime = currentTimestamp - previousTimestamp;
const scrollY = scrollSpeedPerSecond / 1000 * (currentTimestamp - previousTimestamp);
scroller.scrollBy(0, scrollY);
// Update previous timestamp, so we can diff the next "tick" and see how far we need to scroll on the next invocation
previousTimestamp = new Date().getTime();
// We want to only allow recursive calling of itself (basically like a setInterval, when:
// 1. We have not scrolled to the end of the scroller
// 2. The `allowScroll` flag is set to true
if (
// 1
scroller.scrollTop < scroller.scrollHeight - scroller.clientHeight &&
// 2
allowScroll
) {
window.requestAnimationFrame(scrollStep);
}
}
// Call scrolling logic onload
window.requestAnimationFrame(scrollStep);
// Interrupt scrolling when certain events are detected
function pauseScrolling() {
allowScroll = false;
// After a fixed amount of time, we allow resuming of scrolling
window.setTimeout(() => {
allowScroll = true;
previousTimestamp = new Date().getTime();
window.requestAnimationFrame(scrollStep);
}, timeToWaitBeforeResumeScrolling);
}
window.addEventListener('mousewheel', pauseScrolling);
document.addEventListener('touchend', pauseScrolling);
body {
margin: 0;
padding: 0;
}
#wrapper {
overflow: hidden;
width: 100vw;
height: 100vh;
position: absolute;
}
#content_inside_wrapper {
width: 100%;
height: 3000px;
background-image:
linear-gradient(0deg, rgba(255,255,255,0) 98%, rgba(255,255,255,1) 98%),
linear-gradient(0deg, red, orange, yellow, green, blue, purple);
background-size: 100% 50px, 100% 100%;
}
<div id="wrapper">
<div id="content_inside_wrapper">
</div>
</div>