博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
使用requestAnimationFrame来提升动画性能
阅读量:5956 次
发布时间:2019-06-19

本文共 2978 字,大约阅读时间需要 9 分钟。

传统动画的弊端

在实际项目中我们经常会遇到生成动画的需求,传统方法是通过使用setTimeout和setInterval进行实现,但是定时器动画有两个弊端:

  • 时间间隔并不好拿捏,设置太短浏览器重绘频率太快会产生性能问题,太慢的话又显得像PPT不够平滑,业界推荐的时间间隔是16.66...(显示器刷新频率是60Hz,1000ms/60)
  • 浏览器UI线程堵塞问题,如果UI线程之中有很多待完成的渲染任务,所要执行的动画就会被搁置。

为了解决这些问题HTML5加入了requestAnimationFrame

requestAnimationFrame?

window.requestAnimationFrame() 方法告诉浏览器您希望执行动画并请求浏览器在下一次重绘之前调用指定的函数来更新动画。该方法使用一个回调函数作为参数,这个回调函数会在浏览器重绘之前调用。

  • requestAnimationFrame会把每一帧中的所有DOM操作集中起来,在一次重绘或回流中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率

  • 在隐藏或不可见的元素中,requestAnimationFrame将不会进行重绘或回流,这当然就意味着更少的CPU、GPU和内存使用量

  • requestAnimationFrame是由浏览器专门为动画提供的API,在运行时浏览器会自动优化方法的调用,并且如果页面不是激活状态下的话,动画会自动暂停,有效节省了CPU开销

用法

你可以直接调用requestAnimationFrame(),也可以通过window来调用window.requestAnimationFrame()。 requestAnimationFrame()接收一个函数作为回调,返回一个ID值,通过把这个ID值传给window.cancelAnimationFrame()可以取消该次动画。

MDN上给的例子:

var start = null;var element = document.getElementById('SomeElementYouWantToAnimate');element.style.position = 'absolute';function step(timestamp) {  if (!start) start = timestamp;  var progress = timestamp - start;  element.style.left = Math.min(progress / 10, 200) + 'px';  if (progress < 2000) {    window.requestAnimationFrame(step);  }}复制代码

例子

我们来试试生成一个旋转并逐渐变窄的方块,当窄到一定程度又会复原循环往复。

var rotate = 0;var width = 400;var element = document.getElementById('box');function step(timestamp) {    rotate += 10    element.style.transform = `rotate(${rotate}deg)`;    window.requestAnimationFrame(step);}function small(timestamp) {    width = width - 1    element.style.width = width + 'px';    if (width <= 50) {        window.requestAnimationFrame(big);    } else {        window.requestAnimationFrame(small);    }}function big() {    width = width + 1    element.style.width = width + 'px';    if (width >= 400) {        window.requestAnimationFrame(small);    } else {        window.requestAnimationFrame(big);    }}window.requestAnimationFrame(step);window.requestAnimationFrame(small);复制代码

浏览器兼容情况

我们来看一下上的兼容情况:

requestAnimationFrame的兼容情况还是不错的(看不见IE)

如果非要兼容IE的话可以用定时器来做一下兼容:

(function () {    var lastTime = 0;    var vendors = ['webkit', 'moz'];    for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {        window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'];        window.cancelAnimationFrame =            window[vendors[x] + 'CancelAnimationFrame'] || window[vendors[x] + 'CancelRequestAnimationFrame'];    }    if (!window.requestAnimationFrame)        window.requestAnimationFrame = function (callback) {            /*调整时间,让一次动画等待和执行时间在最佳循环时间间隔内完成*/            var currTime = new Date().getTime();            var timeToCall = Math.max(0, 16 - (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);        };}());复制代码

转载地址:http://hyrxx.baihongyu.com/

你可能感兴趣的文章
2018年尾总结——稳中成长
查看>>
JFreeChart开发_用JFreeChart增强JSP报表的用户体验
查看>>
度量时间差
查看>>
通过jsp请求Servlet来操作HBASE
查看>>
Shell编程基础
查看>>
Shell之Sed常用用法
查看>>
3.1
查看>>
校验表单如何摆脱 if else ?
查看>>
<气场>读书笔记
查看>>
web安全问题分析与防御总结
查看>>
Centos下基于Hadoop安装Spark(分布式)
查看>>
3D地图的定时高亮和点击事件(基于echarts)
查看>>
mysql开启binlog
查看>>
设置Eclipse编码方式
查看>>
分布式系统唯一ID生成方案汇总【转】
查看>>
并查集hdu1232
查看>>
Mysql 监视工具
查看>>
从前后端分离到GraphQL,携程如何用Node实现?\n
查看>>
Linux Namespace系列(09):利用Namespace创建一个简单可用的容器
查看>>
博客搬家了
查看>>