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