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

时间:2015-03-04 16:13:17

标签: javascript requestanimationframe

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

我发现Jed Schmidt的这种填充物:https://gist.github.com/997619

保罗·爱尔兰的这一个:http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/

但说实话,我不知道如何用它来创造流畅的效果。在过去我检查了一些插件:nicescroll(我不喜欢它,因为它改变了滚动条样式),smoothscroll.js(这个只能在Chrome上运行),还有一些只能在鼠标滚轮上工作,但是当你点击时没有Re Pag,Av Pag,空格键等等。

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

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

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等时,我只需要做出更好的改进就可以获得这种平滑的效果。

1 个答案:

答案 0 :(得分:2)

我有办法按照我的预期做到这一点:

// 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管理栏,它会将内容置于管理栏下,并在页脚后留下空格。