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