Javascript setTimeout无法正常工作,滚动顺畅

时间:2014-04-29 14:15:29

标签: javascript settimeout

我已经制作了以下凌乱的javascript,它应该能够在div上方平滑地滚动页面128px。

该脚本将页面滚动到正确的位置,但没有顺利。

这是因为我无法使函数setTimeout正常工作。

function pageScroll()
{   
    var from_top=$("#body_box_title_skills").offset().top;  

    scroll_speed = 15;
    goto_px = from_top - 128;

    times_scroll = goto_px / scroll_speed; 
    times_scroll = times_scroll.toString();

    times_scroll_array = times_scroll.split(".");
    times_scroll_array[1] = "0."+times_scroll_array[1];

    px_scroll_extra = times_scroll_array[1] * scroll_speed;

    scrollto_px = 0;

    while (times_scroll_array[0] >= 1)
    {
        scrollto_px = scrollto_px + scroll_speed;
        setTimeout(function(){window.scrollTo(0,scrollto_px)}, 1000);
        times_scroll_array[0]--;
    }
    scrollto_px = scrollto_px + px_scroll_extra;
    window.scrollTo(0,scrollto_px);

}

2 个答案:

答案 0 :(得分:1)

您的问题是,您正在关注scrollto_px中的同一变量setTimeout。当setTimeout函数实际运行时,scrollto_px的值与它在循环结束时的值相同,因此您只需立即滚动到最后一个值。您需要复制到setTimeout可以关闭的新变量。

你的第二个问题是你正在设置一个几乎在同一时间触发的超时。您需要将超时链接起来,以便在1000秒后发生第一次超时,然后在1000秒后发生下一次超时。请注意,setTimeout与其他语言中的sleep不同。它不会暂停执行。

你的第三个问题是你有以下几行:

scrollto_px = scrollto_px + px_scroll_extra;
window.scrollTo(0,scrollto_px);

在你的while循环之后,它将自动一直跳到最后。

这是解决您遇到的问题的一种方法。我删除了你的while循环,并添加了一个在超时后再次调用自身的函数:

function doScroll() {
    if (times_scroll_array[0] >= 1) {
        scrollto_px = scrollto_px + scroll_speed;
        console.log(scrollto_px);
        window.scrollTo(0, scrollto_px);
        times_scroll_array[0]--;
        setTimeout(doScroll, 100);
    } else {
        scrollto_px = scrollto_px + px_scroll_extra;
        window.scrollTo(0, scrollto_px);
    }
}
doScroll();

你可以看到它在这里运行(我改变了时间因为步骤之间的1秒非常慢 - 但你可以根据需要进行调整):http://jsfiddle.net/KqRwx/

答案 1 :(得分:0)

问题在于,当您运行该函数时,整个函数将在触发任何超时之前完整运行。 你真正想要的是这样的东西

function pageScroll(goto_px) {   
    var current_scroll = ( (window.pageYOffset || document.documentElement.scrollTop) - (document.documentElement.clientTop || 0) );
    var scroll_speed = 15;
    // if we are less then 15 px from the destination, scroll whatever is left to go
    if ( Math.abs(goto_px - current_scroll) <= scroll_speed) {
        window.scrollTo(0, goto_px);
    } else {
        // scroll 15 pixels in the direction where the destination is
        window.scrollTo(0, current_scroll + ((current_scroll < goto_px ? 1 : -1) * scroll_speed) );
        window.setTimeout(function(){pageScroll(goto_px)}, 1000);
    }
}


pageScroll( $("#body_box_title_skills").offset().top - 128 );

基本上,使用目标调用函数,该函数计算窗口的当前位置,并向目标滚动一次,并创建一个超时调用自身。 这个功能绝不是完美的,因为你可以通过在相反的方向调用滚动来轻松获得无限循环,在这种情况下,你只需向后滚动,向后滚动到无穷大。应采取其他步骤以确保一次只运行一个实例。

在平滑滚动的中间手动滚动页面将导致页面继续滚动直到到达目的地,并且由于窗口而听取滚动事件以取消超时似乎不是可行的解决方案。 scrollTo也会触发它。一个想法是跟踪当前滚动并在意外跳转时取消超时。

另外请注意:我不确定requestAnimationFrame是否适用于此处,但为了获得一致,尽可能平滑动画,这是您想要使用的内容。可能值得一读。