动画原理: 计算机每16.7ms刷新一次,由于人眼的视觉停留,所以看起来是流畅的移动。
屏幕刷新频率: 屏幕每秒出现图像的次数,大多数电脑显示器的刷新频率是60Hz,大概相当于每秒钟重绘60次。大多数浏览器都会对重绘操作加以限制,不超过显示器的重绘频率,因为即使超过那个频率用户体验也不会有提升。因此,最平滑动画的最佳循环间隔是1000ms/60,约等于16.7ms
实现动画效果的方法比较多,Javascript 中可以通过定时器
来实现,css3 可以使用 transition
和 animation
来实现,html5 中的 canvas
也可以实现。除此之外,html5 还提供一个专门用于请求动画的API,那就是 requestAnimationFrame
,顾名思义就是请求动画帧。
setTimeout和setInterval的问题是,它们都不精确。它们的内在运行机制决定了时间间隔参数实际上只是指定了把动画代码添加到浏览器UI线程队列中以等待执行的时间。如果队列前面已经加入了其他任务,那动画代码就要等前面的任务完成后再执行。
requestAnimationFrame采用系统时间间隔,保持最佳绘制效率,不会因为间隔时间过短,造成过度绘制,增加开销;也不会因为间隔时间太长,使用动画卡顿不流畅,让各种网页动画效果能够有一个统一的刷新机制,从而节省系统资源,改善视觉效果。
questAnimationFrame(callback);
requestAnimationFrame的用法与settimeout很相似,只是不需要设置时间间隔而已
若你想在浏览器下次重绘之前继续更新下一帧动画,那么回调函数自身必须再次调用requestAnimationFrame()
callback
下一次重绘之前更新动画帧所调用的函数(即上面所说的回调函数)。该回调函数会被传入DOMHighResTimeStamp
参数,该参数与requestAnimationFrame()
开始去执行回调函数的时刻。
在同一个帧中的多个回调函数,它们每一个都会接受到一个相同的时间戳,即使在计算上一个回调函数的工作负载期间已经消耗了一些时间。该时间戳是一个十进制数,单位毫秒,最小精度为1ms(1000μs)。请确保总是使用第一个参数(或其它获得当前时间的方法)计算每次调用之间的时间间隔,否则动画在高刷新率的屏幕中会运行得更快。
一个 long
整数,请求 ID ,是回调列表中唯一的标识。是个非零值,没别的意义。你可以传这个值给 window.cancelAnimationFrame()
以取消回调函数。
<div class="progress-wrap"><div class="progress" id="progress"></div>
</div>
<div class="controls"><button id="start">start</button><button id="stop">stop</button><button id="reset">reset</button>
</div>
* {margin: 0;padding: 0;
}
.progress-wrap {background: #eee;height: 50px;
}
.progress-wrap .progress {background: green;width: 0;height: 100%;
}
const domProgress = document.querySelector('#progress')
let progressStep = 0
let timer = ''function progress(timeStamp) {if(progressStep <= 100) {domProgress.style.width = `${progressStep}%`progressStep++timer = questAnimationFrame(progress)}
}document.querySelector('#start').onclick = () => {window.cancelAnimationFrame(timer)timer = questAnimationFrame(progress)
}
document.querySelector('#stop').onclick = () => {window.cancelAnimationFrame(timer)
}
document.querySelector('#reset').onclick = () => {window.cancelAnimationFrame(timer)domProgress.style.width = 0progressStep = 0timer = ''
}
通过设定间隔时间来不断改变图像位置,达到动画效果。但是容易出现卡顿、抖动的现象。原因是:
由系统决定回调函数的执行时机。60Hz的刷新频率,那么每次刷新的间隔中会执行一次回调函数,不会引起丢帧,不会卡顿
CPU节能: 使用setTimeout实现的动画,当页面被隐藏或最小化时,setTimeout 仍然在后台执行动画任务,由于此时页面处于不可见或不可用状态,刷新动画是没有意义的,完全是浪费CPU资源。
而requestAnimationFrame则完全不同。当页面运行在后台标签页或者隐藏的<iframe>
,该页面的屏幕刷新任务也会被系统暂停,因此跟着系统步伐走的requestAnimationFrame也会停止渲染,当页面被激活时,动画就从上次停留的地方继续执行,有效节省了CPU开销,提高性能和电池寿命。
函数节流: 在高频率事件(resize,scroll等)中,为了防止在一个刷新间隔内发生多次函数执行,使用requestAnimationFrame可保证每个刷新间隔内,函数只被执行一次,这样既能保证流畅性,也能更好的节省函数执行的开销。
集中重绘或回流: requestAnimationFrame会把每一帧中的所有DOM操作集中起来,在一次重绘或回流中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率
由于兼容性问题,需要降级对接口进行封装,优先使用高级特性,再根据浏览器不同情况进行回退,直到只能使用setTimeout。
简单处理
if (!questAnimationFrame) {requestAnimationFrame = function(fn) {setTimeout(fn, 16.7);};
}
进一步处理
if(!questAnimationFrame){var lastTime = questAnimationFrame = function(callback){var currTime = new Date().getTime();var timeToCall = Math.max(0, 16.7 - (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);};
}
本文发布于:2024-01-31 14:05:44,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170668114729063.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |