我正在使用全屏滚动脚本。它应该以固定的步骤滚动到上一个或下一个元素,每个元素通常占据页面的整个高度。 This is a good example.
我有一个滚动事件回调,其中包含动画scrollTop
,再次触发滚动事件并陷入循环。我尝试了一些诸如标志的操作,但似乎没有一种对我有用。
这里是代码:
function pageDown() {
// Some stuff, not important
if (currentIndex+1 === pageCount) nextIndex = 0;
else nextIndex = currentIndex+1;
nextPage = $pages.eq(nextIndex);
// Important stuff
$('html body').animate({
scrollTop: nextPage.offset().top
}, 400, function() {preventScroll=false});
}
function pageUp() {
// Some stuff, not important
if (currentIndex === 0) nextIndex = pageCount-1;
else nextIndex = currentIndex-1;
nextPage = $pages.eq(nextIndex);
// Important stuff
$('html body').animate({
scrollTop: nextPage.offset().top
}, 400, function() {preventScroll=false});
}
var lastScroll = 0,
preventScroll = false;
$(window).on('scroll', function() {
var currentScroll = $(window).scrollTop();
if(!preventScroll) {
preventScroll = true;
if (currentScroll > lastScroll) pageDown();
else pageUp();
}
lastScroll = currentScroll;
});
我在测试时看到的主要问题是,jQuery的complete
的animate
回调在其生成的最终scroll
事件之前触发。请注意,这似乎仅在出于某些原因向下滚动时发生。
[实验了2个步骤的锁之后,我使用了带有3个状态的标志来取消最终的scroll
事件,该事件效果很好,我进一步进行了探索,因为它与原始版本中存在的翻转逻辑不太合作代码(到达末尾时跳到另一端)。
我想出了以下代码,该代码记录了要达到的目标位置,并忽略了所有scroll
事件,只要当前位置与目标位置不匹配。
这还实现了翻转逻辑,并且必须与关联的HTML和CSS结合才能正常工作,因为我们需要一些空格(此处每侧各有一个像素)以允许在scroll
事件被触发顶部和底部。我们还启动了第一滚动,以正确定位第一个元素并允许翻转立即进行。
我希望代码中的注释将提供理解所使用的逻辑所必需的附加信息。
此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)