1. 程式人生 > 實用技巧 >requestAnimationFrame節流,優化scroll和touchmove事件

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