requestAnimationFrame动画控制详解

本文介绍了requestAnimationFrame的起源和发展历程,对比了其与setInterval在动画控制上的优势,并提供了兼容性解决方案和示例代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

还在使用setInterval吗,你out了,requestAnimationFrame可以实现更为经济、更加准确的控制动画,今天来看看它的来龙去脉。


以往

在web动画、app动画中,我们经常通过setInterval或setTimeout定时修改DOM、CSS实现动画,如下面代码所示。

var timer=setInterval(function(){
   //一些动画
},1000/60)
//清除动画
clearInterval(timer);

不过如此动画的方式极为耗费资源,经常是这样的结果,刚开始比较流畅,5分钟之后动画就卡住了,于是“大家”都看不下去了,开始想这种办法。

简介

2011年左右,Paul Irish的《 requestAnimationFrame for Smart Animating 》首先介绍了requestAnimationFrame的使用,然后经过大家的努力《 Timing control for script-based animations 》在2013年成为了w3c的候选标准。

requestAnimationFrame的方式的优势如下:

1.经过浏览器优化,动画更流畅

2.窗口没激活时,动画将停止,省计算资源

3.更省电,尤其是对移动终端

requestAnimationFrame的使用方式,简单调用代码如下。 

function animate() {
  // Do whatever
  requestAnimationFrame(animate);
  // Do something animate
  
}
//go->
requestAnimationFrame(animate);

有的时候我们必须要加一些控制, requestAnimationFrame也可以像setInterval一样返回一个句柄,然后我们可以取消它。控制动画代码如下。

var globalID;
function animate() {
  // Do whatever
  globalID=requestAnimationFrame(animate);
  // Do something animate
  
}
//when ot start
  globalID=requestAnimationFrame(animate);
//when to stop
  cancelAnimationFrame(globalID);

好了,介绍完了吧。先别走,对于一个前端开发者,我们不能如此“单纯”,因为浏览器太任性,谁知道这些浏览器都是怎么“想的”,我们要看看浏览器兼容情况。来上CanIUse 。


桌面端除了万恶的IE系列低版本9-,移动端除了Opera Mini和Android Browser4.3-其他都支持。总支持率83.38%,不加前缀支持率81.98%,支持率不错。作为一个富有极客精神的前端er,我们还得继续,拯救那些“手里没钱、手里有权却榆木疙瘩,还在使用低版本浏览器”的同胞,来个 polyfill 。

补丁

Paul Irish的简化版的补丁,补丁和使用如下代码所示。

// 补丁
window.requestAnimationFrame = (function(){
  return  window.requestAnimationFrame       ||
          window.webkitRequestAnimationFrame ||
          window.mozRequestAnimationFrame    ||
          function( callback ){
            window.setTimeout(callback, 1000 / 60);
          };
})();


// 使用

(function animate(){
  requestAnimationFrame(animate);
  //动画
})();

这个补丁可以较好的兼容支持该特性的浏览器,但是对于不支持的呢?这里讲了怎么添加,如何停止呢?于是我们的补丁还得继续……

(function() {  
  var lastTime = 0;  
  var vendors = ['ms', 'moz', 'webkit', 'o'];  
  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, element) {  
      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);  
    };  
}());

有后来,又有了新更新,大家到 github查看详情 ,代码贴过来,大家研究。

// requestAnimationFrame polyfill by Erik Möller.
// Fixes from Paul Irish, Tino Zijdel, Andrew Mao, Klemen Slavič, Darius Bacon
// MIT license
if (!Date.now)
  Date.now = function() { return new Date().getTime(); };
(function() {
  'use strict';
  var vendors = ['webkit', 'moz'];
  for (var i = 0; i < vendors.length && !window.requestAnimationFrame; ++i) {
    var vp = vendors[i];
    window.requestAnimationFrame = window[vp+'RequestAnimationFrame'];
    window.cancelAnimationFrame = (window[vp+'CancelAnimationFrame']
                   || window[vp+'CancelRequestAnimationFrame']);
  }
  if (/iP(ad|hone|od).*OS 6/.test(window.navigator.userAgent) // iOS6 is buggy
    || !window.requestAnimationFrame || !window.cancelAnimationFrame) {
    var lastTime = 0;
    window.requestAnimationFrame = function(callback) {
      var now = Date.now();
      var nextTime = Math.max(lastTime + 16, now);
      return setTimeout(function() { callback(lastTime = nextTime); },
                nextTime - now);
    };
    window.cancelAnimationFrame = clearTimeout;
  }
}());
### 回答1: `requestAnimationFrame` 是一个浏览器 API,它可以让你的 JavaScript 在下一个浏览器重绘之前运行。这样可以有效地提高动画的性能,因为它可以让浏览器在重绘之前知道你的动画需要做什么。使用`requestAnimationFrame`可以避免浏览器的重绘和回流,提高动画的流畅度。 使用方法: ``` // 定义动画函数 function animate() { // 在这里编写动画代码 requestAnimationFrame(animate); } // 开始动画 requestAnimationFrame(animate); ``` 注意:不同浏览器有不同的实现,如果不支持`requestAnimationFrame`,可以使用`setTimeout`或`setInterval`来模拟。 ### 回答2: requestAnimationFrame 是用来代替 setTimeout 或 setInterval 的一种优化方案,它可以让Javascript在浏览器的下一次重绘之前执行某个函数,以达到最佳的渲染效果。 它的优点在于可以让浏览器在渲染性能的限制下自动调整,以便保持每秒渲染帧率在60FPS左右,从而有效避免掉帧现象,一定程度上优化体验。 使用 requestAnimationFrame 的语法如下: window.requestAnimationFrame(callback); 其中,callback 是在下一帧渲染时要执行的函数,它会自动传入一些参数,例如时间戳等。 具体来说,requestAnimationFrame 的工作原理是这样的: 1. 当 Javascript 代码执行到 window.requestAnimationFrame() 时,会把回调函数放到一个队列里面等待执行。 2. 浏览器在下一次重绘之前会检查这个队列,如果队列里有函数,就执行这些函数,否则什么也不做。 3. 如果函数执行的过程中或执行完成后,将再次请求下一帧的重绘。 有了 requestAnimationFrame,我们就可以编写更加流畅自然的动画效果,而不必担心因为性能瓶颈导致掉帧,从而达到更好的用户体验。同时,它也可以有效避免由于 setInterval 或 setTimeout 过于频繁地操作Dom节点而引起的性能问题。不过值得注意的是,requestAnimationFrame 并不支持 IE9 及以下版本的浏览器,因此在进行兼容性考虑时需要引入 polyfill 或使用其他方案。 ### 回答3: requestAnimationFrame(简称RAF)是一种用于浏览器动画效果的方法。该方法通过以比setInterval更优秀的方式在浏览器下一次渲染时刻之前更新动画效果,以使动画流畅自然。在一些高要求的场景下,使用setTimeout和setInterval往往会导致更新不及时;而使用requestAnimationFrame可以保证效果在下一次渲染时完成,确保页面更新及时、不丢帧。 requestAnimationFrame的主要特点是: - 操作DOM次数减少,增强性能 - 优化页面动画,避免出现卡顿现象 - 适用于各种各样的动画效果 - 减少了原来程序需要处理时间,使得程序变得更加高效 requestAnimationFrame最大的优点是:在页面未找到其他的任务时,一次帧效果可以达到每秒60帧,基本上和显示器的刷新频率相匹配。此外,requestAnimaitonFrame会自动适应浏览器窗口大小的变化,并且可以在各种设备上正常工作。另外,requestAnimationFrame还可以在浏览器最小化、后台挂起等情况下暂停,以节省计算资源。 使用requestAnimationFrame的步骤如下: 1.调用requestAnimationFrame函数,并带有一个函数作为参数 2.在函数中改变元素属性或是Canvas的状态和图像/文本内容 3.使浏览器执行函数 使用requestAnimationFrame的方法一般都遵循“递归调用”的设计模式。就是说每次执行函数时都会加入下一个临界点循环,递归执行直到某个条件终止。 总之,requestAnimationFrame是一种比setTimeout更优秀的动画效果控制方法,其优点是高效、流畅,对于大多数的动画效果是一个很好的选择。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值