柔滑流畅的JavaScript动画的秘密!

requestAnimationFrame

柔滑流畅的JavaScript动画的秘密!

用JavaScript创建动画是你可以做的最简单的事情之一。如果你曾经尝试过这样做,那么你很可能已经使用过setTimeout或者setInterval功能。

这是一个典型的例子:

函数 draw  { 
    //绘图代码在这里
} 
setInterval  draw  100 ;

这段代码会draw每100ms永远调用一次函数,直到稍后clearInterval调用函数。此代码的替代方法是使用setTimeout函数,而不是此draw函数内部

函数 draw  { 
    setTimeout  draw  100 ; 
    //绘制代码在这里
} 
draw ;

draw函数的单个调用会启动动画循环,从此它将每100ms重复一次。

帧速率和setInterval

动画的平滑度取决于动画的帧速率。帧速率以每秒帧数(fps)来衡量。电影通常运行速度为24fps,视频速度为30fps。这个数字越高,动画看起来就越平滑。更多的帧,意味着更多的处理,这往往会导致口吃和跳跃。这就是丢帧的意思。由于大多数屏幕的刷新频率为60Hz,所以您应该瞄准的最快帧频为60fps。有些数学的时间!

/ **
 * 1s = 1000ms(请记住,setInterval和setTimeout以毫秒运行)
 * 1000ms / 60(fps)= 16.7ms(我们将它舍入为17)
 * /
 
//灯光,相机...功能!
setInterval function  { 
    animateEverything ; 
}  17 ;

setTimeout和setInterval有什么问题?

好的,你以前做过这一百万次了。这张照片有什么问题?好吧,有几件事。首先,setTimeout不考虑浏览器中发生了什么。该页面可能隐藏在标签后面,在不需要时占用CPU,或者动画本身可能已从页面滚动到不再需要更新呼叫。Chrome会在隐藏的标签中进行缩小setIntervalsetTimeout1fps,但这不是所有浏览器都需要依赖的。

其次,setTimeout只在需要时更新屏幕,而不是在计算机能够时更新。这意味着您的浏览器不得不在重画整个屏幕时重新绘制动画,并且如果您的动画帧速率与重新绘制屏幕不同步,则可能需要更多的处理能力。这意味着更高的CPU使用率和计算机的风扇,或移动设备上的电池耗尽。Nicolas Zakas在解释定时器分辨率对相关文章中动画的影响方面做得非常出色

另一个考虑是一次动画多个元素。解决这个问题的一种方法是将所有动画逻辑放置在一个区间中,并理解即使特定元素可能不需要用于当前帧的任何动画,也可以运行动画调用。另一种方法是使用不同的时间间隔。这种方法的问题在于,每次在屏幕上移动某个东西时,浏览器都必须重新绘制屏幕。这太浪费了!

requestAnimationFrame来拯救!

为了克服这些效率问题,Mozilla(Firefox制造商)提出了该requestAnimationFrame功能,后来由WebKit团队(Chrome和Safari)采用并改进了该功能。它提供了一个本机API,用于在浏览器中运行任何类型的动画,可以使用DOM元素,CSS,canvas,WebGL或其他任何类型的动画。

以下是您如何使用它的方法:

函数 draw  { 
    requestAnimationFrame  draw ; 
    //绘制代码在这里
} 
draw ;

大!它和setTimeout版本完全一样,但是requestAnimationFrame代之以。或者,您可以将参数传递给被调用的函数,例如当前元素正在被动画,如下所示:requestAnimationFrame(draw, element);

您可能已经注意到了,但您并未指定间隔比率。那么这个draw函数多久调用一次?这一切都取决于您的浏览器和计算机的帧速率,但通常是60fps(这是很酷的,因为您的计算机的显示器通常以60Hz的速率刷新)。这里的关键区别在于,您正在请求浏览器在下一个可用机会绘制动画,而不是以预定间隔绘制也有人暗示,浏览器可以选择requestAnimationFrame基于负载,元素可见性(滚动出视图)和电池状态来优化性能

另外一个好处requestAnimationFrame就是它将所有的动画组合成一个浏览器重绘。这节省了CPU周期,并让您的设备过上更长久,更幸福的生活。

所以,如果你使用requestAnimationFrame所有的动画应该变得如丝般顺滑,与你的GPU同步,CPU少得多。如果你浏览到一个新标签页,浏览器会将动画限制为抓取,从而防止它在繁忙时占用计算机。好极了!

听起来很棒!任何问题?

嗯,是。因为这是一个新的API,它目前只能通过供应商前缀在浏览器中使用,例如webkitRequestAnimationFrame在Chrome和Safari中以及mozRequestAnimationFrame在Firefox中。浏览器支持并不糟糕,甚至微软也会支持msRequestAnimationFrameIE 10的版本。

为了避开不同的支持,埃里克·默勒(歌剧),保罗·爱尔兰(谷歌)和蒂诺Zijdel(Tweakers.net)已经创建了一个填充工具,使之简单再次使用:

// http://paulirish.com/2011/requestanimationframe-for-smart-animating/ 
// http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-动画
 
// 
ErikMöller // requestAnimationFrame polyfill //由Paul Irish和Tino Zijdel修复
 
函数 { 
    VAR lastTime =  0 ; 
    VAR厂商=  [ 'MS'  'MOZ'  '的webkit'  'O' ] ; 
    对于VAR X =  0 ; X <。厂商长度 &&  。窗口requestAnimationFrame ;  + + X  { 
        窗口。requestAnimationFrame  =窗口[厂商[ X] + 'RequestAnimationFrame' ] ; 
        窗口。cancelAnimationFrame  = window [ vendors [ x ] + 'CancelAnimationFrame' ] 
                                   || 窗口[ vendors [ x ] + 'CancelRequestAnimationFrame' ] ; 
    }
 
    如果 窗口。requestAnimationFrame  
        窗口。requestAnimationFrame  =  function  callback  element  { 
            var currTime =  new  Date getTime ; 
            var timeToCall =  Math最大值0  16  -   currTime - lastTime ; 
            var id = window。setTimeout function  { callback  currTime + timeToCall ;  }  
              timeToCall ; 
            lastTime = currTime + timeToCall ; 
            返回 ID ; 
        } ;
 
    如果 窗口。cancelAnimationFrame  
        窗口。cancelAnimationFrame  =  function  id  { 
            clearTimeout  id ; 
        } ; 
} ;

把它放到你的代码中,你可以使用requestAnimationFrame作为自然意图

一个简单的垫片是可用的,它只使用a setTimeout作为后备。这也可以,只要你requestAnimationFrame在循环的开始而不是结束时调用如果你不这样做,Opera的ErikMöller解释道,动画时序可能变得不可预测因此,坚持上面的更新可能会更好:)

如果我想设置帧速率怎么办?

剩下的一个明显问题是:requestAnimationFrame如果您无法指定帧速率,如何控制动画的时间游戏通常需要特定的帧率来制作动画。

停止!在跑回去之前setInterval,您可以使用以下技巧:

var fps =  15 ; 
函数 draw  { 
    setTimeout function  { 
        requestAnimationFrame  draw ; 
        //绘图代码在这里
    }  1000  / fps ; 
}

通过包装requestAnimationFrame在一个setTimeout你有你的鱼与熊掌兼得。您的代码可以节省效率,并且可以指定帧速率,最高可达60fps。

更复杂的技术是检查自上次绘制调用以来的毫秒数,并根据时间差异更新动画的位置。例如:

var time ; 
函数 draw  { 
    requestAnimationFrame  draw ; 
    var now =  new  Date getTime  
        dt = now -   time || now ;
 
    时间=现在;
 
    //绘图代码在这里...例如更新'x'位置:
    这个x  + =  10  * dt ;  //增加'x'每毫秒10个单位
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值