防止使用jQuery时由动画scrollTop触发滚动事件

问题描述 投票:3回答:1

我正在使用全屏滚动脚本。它应该以固定的步骤滚动到上一个或下一个元素,每个元素通常占据页面的整个高度。 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;
});
javascript jquery
1个回答
2
投票

我在测试时看到的主要问题是,jQuery的completeanimate回调在其生成的最终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)
© www.soinside.com 2019 - 2024. All rights reserved.