如何使用requestAnimationFrame实现平滑滚动?

How to implement a smooth scroll using requestAnimationFrame?

我想在我的网页中制作一个很好的平滑滚动效果,我发现最好的方法之一是使用 requestAnimationFrame。

我找到了 Jed Schmidt 的这个 polyfill:https://gist.github.com/997619

这是 Paul Irish 的作品:http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/

但说实话,我不知道如何使用它来创建平滑效果。过去我检查了一些插件:nicescroll(我不喜欢它,因为它改变了滚动条的样式),smoothscroll.js(这个只适用于 Chrome),还有一些只适用于鼠标滚轮,但当您单击 Re Pag、Av Pag、空格键等时则不会。

我可以在此页面上提供示例:http://cirkateater.no/ 滚动效果非常好并且工作效率很高。它也是跨浏览器的!但是看它的JS代码,只看到了一个巨大的parallax函数,不知道我要的是不是这个函数。

你能告诉我从哪里开始吗?我会在这里更新进度。

PD:实际上,我花了一天时间尝试通过将复制粘贴到我的 scripts.js 文件中的无意义操作来实现它。我不是 JS 专家,但我推断这很难做到。

编辑 1: 我已经有了一些东西。首先,polyfill:

(function() {
var lastTime = 0;
var vendors = ['ms', 'moz', 'webkit', 'o'];
for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
    window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
    window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame']
                               || window[vendors[x]+'CancelRequestAnimationFrame'];
}

if (!window.requestAnimationFrame)
    window.requestAnimationFrame = function(callback, element) {
        var currTime = new Date().getTime();
        var timeToCall = Math.max(0, 16 - (currTime - lastTime));
        var id = window.setTimeout(function() { callback(currTime + timeToCall); },
          timeToCall);
        lastTime = currTime + timeToCall;
        return id;
    };

if (!window.cancelAnimationFrame)
    window.cancelAnimationFrame = function(id) {
        clearTimeout(id);
    };
}());

平滑的鼠标滚轮:

var html = document.documentElement;
var rAF, target = 0, scroll = 0;

onmousewheel = function (e) {
e.preventDefault();
var scrollEnd = html.scrollHeight - html.clientHeight;
target += (e.wheelDelta > 0) ? -70 : 70;
if (target < 0)
    target = 0;
if (target > scrollEnd)
    target = scrollEnd;
if (!rAF)
    rAF = requestAnimationFrame(animate);
};

onscroll = function () {
if (rAF)
    return;
target = pageYOffset || html.scrollTop;
scroll = target;
};

function animate() {
scroll += (target - scroll) * 0.1;
if (Math.abs(scroll.toFixed(5) - target) <= 0.47131) {
    cancelAnimationFrame(rAF);
    rAF = false;
}
scrollTo(0, scroll);
if (rAF)
    rAF = requestAnimationFrame(animate);
}

我们可以从这里开始。现在我只需要做更好的改进,在按方向键、Re Page、Av Page等时,就有这种流畅的效果了

如我所料,我有办法做到这一点:

// http://paulirish.com/2011/requestanimationframe-for-smart-animating/
// http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating

// requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel

// MIT license
(function () {
var lastTime = 0;
var vendors = ['ms', 'moz', 'webkit', 'o'];
for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
    window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'];
    window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame']
        || window[vendors[x] + 'CancelRequestAnimationFrame'];
}

if (!window.requestAnimationFrame)
    window.requestAnimationFrame = function (callback, element) {
        var currTime = new Date().getTime();
        var timeToCall = Math.max(0, 16 - (currTime - lastTime));
        var id = window.setTimeout(function () {
            callback(currTime + timeToCall);
        },
            timeToCall);
        lastTime = currTime + timeToCall;
        return id;
    };

if (!window.cancelAnimationFrame)
    window.cancelAnimationFrame = function (id) {
        clearTimeout(id);
    };
}());


('ontouchend' in document) || jQuery(function($){

var scrollTop = 2, tweened = 0, winHeight = 0, ct = [], cb = [], ch = [], ph = [];
var wrap = $('#wrap').css({position:'fixed', width:'100%', top:0, left:0})[0];
var fake = $('<div>').css({height: wrap.clientHeight}).appendTo('body')[0];

var update = function(){
        window.requestAnimationFrame(update);
        if(Math.abs(scrollTop-tweened) > 1){
            var top = Math.floor(tweened += .25 * (scrollTop-tweened)),
                bot = top + winHeight, wt = wrap.style.top = (top*-1) + 'px';

            for(var i = plax.length; i--;)if(cb[i] > top && ct[i] < bot){
                plax[i].style.top = ((ct[i] - top) / Math.max(ph[i] - ch[i], winHeight - ch[i]) * (ch[i] - ph[i])) + 'px';
            }
        }
    };

var listen = function(el,on,fn){(el.addEventListener||(on='on'+on)&&el.attachEvent)(on,fn,false);};
var scroll = function(){scrollTop = Math.max(0, document.documentElement.scrollTop || window.pageYOffset || 0);};

listen(window, 'scroll', scroll);
update();
});

这是 HTML 结构:

<html>
    <body>
        <div id="wrap">
            <!-- The content goes here -->
        </div>
    </body>
</html>

它有效,但并不完美。例如,为用户启用 WP 管理栏,它会将内容定位在管理栏下,并在页脚后留下空白 space。