requestAnimationFrame节流,优化scroll和touchmove事件

touchmove和scroll事件发生很频繁, 会比屏幕刷新率快, 导致无效的渲染和重绘。
可以使用requestAnimationFrame来优化滚动处理, 在一帧中只进行一次重绘。

1. onScroll用requestAnimationFrame来优化
// rAF触发锁,必须加锁,多次调用raf,会在一帧中多次触发回调
var ticking = false; 
 
function onScroll(){
  if(!ticking) {
    requestAnimationFrame(realFunc);
    ticking = true;
  }
}
 
function realFunc(){
    // do something...
    console.log("Success");
    ticking = false;
}
// 滚动事件监听
window.addEventListener('scroll', onScroll, false);
2. 封装一个raf的动画函数
var lock = {};
function animationFrame (callback = (time) => {}, key = 'default') {
    if (lock[key]) { return false }
    lock[key] = true
    window.requestAnimationFrame((time) => {
        lock[key] = false
        callback(time)
    })
    return true
}

// 调用
window.addEventListener('scroll', () => { animationFrame((time) => doAnimation(time)) })
3. 封装一个raf的throttle方法
var rafThrottle = function(fn) {
    var ticking = false;
    var update = function() {
        ticking = false;
        fn && fn.apply(this, arguments);
    }

    function requestTick() {
        if (!ticking) {
            requestAnimationFrame(update);
        }
        ticking = true;
    }
    requestTick();
}
4. touchmove用requestAnimationFrame优化,一帧只执行一次计算
function drag(element) {
    var startX = 0,
        startY = 0,
        ticking = false,
        raf,
        doc = document;

    element.addEventListener("touchstart", function(e) {
        var e = e || window.event,
            touchs = e.touches[0];
        e.preventDefault(); //低端安卓touch事件有的导致touchend事件时效,必须开始就加 e.preventDefault();
        startX = parseInt(touchs.pageX - (element.lefts || 0));
        startY = parseInt(touchs.pageY - (element.tops || 0));
        doc.addEventListener("touchmove", update, false);
        doc.addEventListener("touchend", end, false);
    }, false);

    var update = function(e) {
        var e = e || window.event;
        if (e.touches.length > 1 || e.scale && e.scale !== 1) return;
        e.preventDefault();
        if (!ticking) {
            var touchs = e.changedTouches[0];
            //1先触摸移动  
            element.lefts = touchs.pageX - startX;
            element.tops = touchs.pageY - startY;
            //2交给requestAnimationFrame 更新位置
            raf = requestAnimationFrame(draw);
        }
        ticking = true;
    };

    var draw = function() {
        ticking = false;
        var nowLeft = parseInt(element.lefts); //滑动的距离touchmove时候,如果加阻力,可能有细小的抖动;我想应该是移动端 部分支持0.5px的缘故;parseInt的转化有点牵强;
        var nowTop = parseInt(element.tops); //滑动的距离    
        element.style.webkitTransform = element.style.transform = "translate3D(" + nowLeft + "px," + nowTop + "px,0px)";
    };

    var end = function() {
        var endLeft = parseInt(element.lefts); //滑动的距离    
        var endTop = parseInt(element.tops); //滑动的距离
        doc.removeEventListener("touchmove", update, false);
        doc.removeEventListener("touchend", end, false);
    }
}
参考:https://cloud.tencent.com/developer/article/1613039
     https://www.cnblogs.com/coco1s/p/5499469.html
     http://www.mamicode.com/info-detail-1256974.html
 
原文地址:https://www.cnblogs.com/mengff/p/13452704.html