I am working on a fullscreen scrolling script. It is supposed to scroll in fixed steps, to the previous or next element, each typically occupying the full height of the page
The main issue I have witnessed when testing this out is that the complete
callback of jQuery's animate
fires before the final scroll
event it generates. Note that seems to only happen when scrolling down for some reason.
After experimenting with a 2 steps lock, where I used a flag with 3 states to cancel that final scroll
event, which worked fairly well, I explored further as it was less cooperative with the rollover logic that is present in your original code (jumping to the opposite end when reaching an end).
I came up with the following code, which records the target position to be reached and ignores all scroll
events as long as the current position does not match the target.
This also implements the rollover logic and must be combined with the associated HTML and CSS to work properly, as we need some blank space (a single pixel on each side here) to allow for a scroll
event to be fired at the top and bottom. We also initiate a first scroll as to correctly position the first element and allow the rollover to work immediately.
I hope the comments in the code will provide the additional information necessary to understand the logic being used.
A working demo is available in this jsfiddle
HTML:
<div class="pageScroller">
<div class="bumper"></div>
<div class="page" style="background-color:red;"></div>
<div class="page" style="background-color:green;"></div>
<div class="page" style="background-color:blue;"></div>
<div class="page" style="background-color:violet;"></div>
<div class="page" style="background-color:cyan;"></div>
<div class="bumper"></div>
</div>
CSS:
html, body {
height:100%;
margin:0;
padding:0;
}
.pages {
padding:1px 0;
background-color:yellow;
}
.pageScroller, .page {
height:100%;
}
.bumper {
height:1px;
}
JavaScript:
var $pages = $('.page');
var currentIndex = 0;
var lastScroll = 0;
var currentScroll = 0;
var targetScroll = 1; // must be set to the same value as the first scroll
function doScroll(newScroll) {
$('html, body').animate({
scrollTop: newScroll
}, 400);
}
$(window).on('scroll', function() {
// get current position
currentScroll = $(window).scrollTop();
// passthrough
if(targetScroll == -1) {
// no target set, allow execution by doing nothing here
}
// still moving
else if(currentScroll != targetScroll) {
// target not reached, ignore this scroll event
return;
}
// reached target
else if(currentScroll == targetScroll) {
// update comparator for scroll direction
lastScroll = currentScroll;
// enable passthrough
targetScroll = -1;
// ignore this scroll event
return;
}
// get scroll direction
var dirUp = currentScroll > lastScroll ? false : true;
// update index
currentIndex += (dirUp ? -1 : 1);
// reached before start, jump to end
if(currentIndex < 0) {
currentIndex = $pages.length-1;
}
// reached after end, jump to start
else if(currentIndex >= $pages.length) {
currentIndex = 0;
}
// get scroll position of target
targetScroll = $pages.eq(currentIndex).offset().top;
// scroll to target
doScroll(targetScroll);
});
// scroll to first element
$(window).scrollTop(1)