Как реализовать плавную прокрутку с помощью requestAnimationFrame?

Я хочу сделать хороший эффект плавной прокрутки на своей веб-странице, и я вижу, что одним из лучших способов является использование requestAnimationFrame.

Я нашел этот полифил Джеда Шмидта: 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: у меня уже есть кое-что. Во-первых, полифилл:

(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 и т. д.


person Gerard    schedule 04.03.2015    source источник


Ответы (1)


У меня есть способ сделать это, как я и ожидал:

// 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, контент будет располагаться под панелью администратора, а после нижнего колонтитула останется пустое место.

person Gerard    schedule 05.03.2015