浅析JavaScript动画


Posted in Javascript onJune 10, 2015

今天,小学生以自己浅薄的见地,在前辈大能的基础上写这篇文章,希望给大家打开一扇窥探JavaScript(以下简称JS)动画的窗户。

JS如何制造出动画效果?

结合浏览器提供的 setInterval 或 setTimeout API,高频改变DOM元素的一些属性,即可创造一个肉眼可见的动画效果。一个看起来非常流畅的JS动画除了需要良好的变换算法外,与其执行宿主也是非不开的。程序写得再好,如果浏览器过于老旧,电脑CPU性能低下,也会出现卡顿,甚至卡死。

执行一个动画函数对于浏览器来说是个苦差,设置动画一帧为多长时间才能既流畅又不损耗性能呢?浏览器不会傻到进行一个DOM操作,就去渲染一次页面。它会把一个周期内所有的DOM操作整合起来,统一进行一次渲染。这个周期大约在16.7ms左右,不同浏览器间会有几毫秒的差异。SetTimeout的第二个参数设置为1000/60是比较合乎情理的做法。不过了解过SetTimeout运行机制的都会清楚,这个时间并不可靠,其根据实际情况会有些许甚至相当大的延迟。那么有没有这样一个API?我不想知道你浏览器到底多久渲染一次,反正你渲染的时候给我的动画执行一帧就行了。答案是有,requestAnimationFrame,可以让函数随着浏览器渲染执行,并且执行时机是可靠的。注意,这个方法在现在浏览器及IE10+才被支持。

现在可以封装起一个简单的requestAnimationFrame,下面的例子中将会使用到它。

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

更加详细的封装可以在张鑫旭的博客中看到:张鑫旭:requestAnimFrame。下面让我们继续。

动画函数的编写

有了requestAnimationFrame,下面该考虑一下如何让写动画函数了。一般来说我们会给出一个毫秒级的during值,限制这个动画必须要在这个时间内完成。下面以实现一个小球从离页面左侧100px处匀速运动到800px处为例,编写一个动画函数:戳我查看DEMO。

var ele = document.getElementById("block");
      var start = Date.now();//获取动画开始的时间。
      var during = 1000; //此动画要在1秒内执行完。
      var p=0;//动画完成度 从0-1;
      requestAnimationFrame(function f(){
        if(p>=1){ ele.style.left="800px";}//如果发现动画已经执行完,将元素置到终点。
        else{
          p=(Date.now()-start)/during;
          ele.style.left=100+700*p+"px"; //从100px开始,匀速向右移动,共移动700px;
          requestAnimationFrame(f);
        }
      })

上面函数中有一个关键变量:p,即percentage,我们可以称它为动画的完成度,它是根据当前时间计算得出的,并且从动画开始后,会从0~1匀速渐变。当其为1时,表示整个动画执行完毕。在这个函数中,让p乘以要运动的长度700,便会得到一个0-700匀速变化的值,将其加上开始的100,便可模拟小球从100px处匀速移动到800px处。

设想一下,假如上面红色标出的运动方程改为“ele.style.left=100+700*p*p+"px"”呢?p以二次方渐增,小球向右移动的速度会越来越快。是的,稍加修改便可实现一个匀加速运动的小球。

下面,我们就是要针对p来做文章。

Tween算法及缓动效果

 

下面我将列举一些常用的缓动算法,根据这些算法去修改上面匀速运动函数的运动方程,即可实现很赞的动画效果。
1.2次方缓动:

p*p
2.3次方缓动:

p*p*p
3.4次方缓动:

p*p*p*p
4.5次方缓动:

p*p*p*p*p
5.正弦曲线缓动:  Math.sin(p*Math.PI/2)
6.指数曲线缓动:  Math.pow(2,10*(p-1))
7.圆形曲线缓动:  Math.sqrt(1-(p-1)*(p-1))
8.超范围三次方:  p*p*(2.70158*p-1.70158)

验证一下吧,比如我现在想实现一个小球向右运动,有一个向左蓄力的动画,我只要把第一个demo的运动方程改为“ele.style.left=100+700*p*p*(2.70158*p-1.70158)+"px"”就行了,看看效果吧:戳我查看DEMO。

其实,每种缓动算法都可以进化为三种缓动方式,分别为ease-in(先慢后快),ease-out(先快后慢),ease-in-out(先慢后快再慢)。

以2次方缓动为例,它本身就是一个匀加速的过程,所以ease-in就是p*p。其ease-out为-(p*(p-2))。关于缓动方式,像阳光一样在他的博客中有更加详细的解释:JavaScript动画、运动算法详细解释与分析。

接下来要放大招了,关于缓动的整合DEMO,戳我吧。

JS动画可以做什么?

除了上面的缓动效果,利用常见的数学公式还可以实现一些周期性运动效果,例如小球匀速圆周运动,小球匀速简谐振动等,如果感兴趣请猛戳DEMO。

那么JS动画可以做什么呢?这就需要发挥我们的个人想象力了,上面的DEMO大部分都在操控单一的属性,比如left,让DOM元素发生位移。事实上在运动方程中,元素的任何style都可以被渐变。试想一下,设置一个DOM元素的opacity从0~1进行2次方缓动,便是一个简单的jQuery fadeOut函数;让一个DOM元素高度从无到有,便是一个简单的jQuery slideDown函数。更加不要忘记的是,在动画过程中不仅仅可以操作一项属性,这为动画带来了无限的可能性,事情变得越来越有趣了:DEMO:一个从小到大变化的球。

再试想一下,使用CSS3属性,例如box-shadow,transform,作出的效果必将会更加绚丽。

总结

上面提到使用CSS3属性,其实如果这个浏览器支持CSS3属性的话,完全没有必要使用JS来做这件事。CSS3自有Animation动画属性,可以简单快捷地实现酷炫的动画效果,并且可以启用GPU加速。美中不足的是仅现代浏览器支持。JS实现动画胜在可以兼容低版本浏览器,但是其效果一般(仅限于普通意义上的动画,不含canvas之类的)。

动画仅仅是JS操作DOM魅力之冰山一角,而数学与计算机总是能碰撞出耀眼的火花。继续学习JS吧,这是一门神奇的语言,同时也应该了解一些数学知识,往往能够为解决事情带来捷径。

以上所述就是本文的全部内容了,希望大家能够喜欢。

Javascript 相关文章推荐
基于javascipt-dom编程 table对象的使用
Apr 22 Javascript
js简单实现删除记录时的提示效果
Dec 05 Javascript
关于js数组去重的问题小结
Jan 24 Javascript
jquery实现多条件筛选特效代码分享
Aug 28 Javascript
jQuery+JSON实现AJAX二级联动实例分析
Dec 18 Javascript
AngularJS中isolate scope的用法分析
Nov 22 Javascript
vue.js入门(3)——详解组件通信
Dec 02 Javascript
基于jQuery实现照片墙自动播放特效
Jan 12 Javascript
angularjs实现柱状图动态加载的示例
Dec 11 Javascript
vue如何实现自定义底部菜单栏
Jul 01 Javascript
vue-cli history模式实现tomcat部署报404的解决方式
Sep 06 Javascript
JavaScript实现九宫格拖拽效果
Jun 28 Javascript
JavaScript操作XML文件之XML读取方法
Jun 09 #Javascript
JavaScript检查数字是否为整数或浮点数的方法
Jun 09 #Javascript
jQuery取消ajax请求的方法
Jun 09 #Javascript
JavaScript动态添加style节点的方法
Jun 09 #Javascript
jQuery实现将页面上HTML标签换成另外标签的方法
Jun 09 #Javascript
Javascript实现div的toggle效果实例分析
Jun 09 #Javascript
js获取字符串字节数方法小结
Jun 09 #Javascript
You might like
聊天室php&mysql(三)
2006/10/09 PHP
php smtp实现发送邮件功能
2017/06/22 PHP
Javascript代码混淆综合解决方案-Javascript在线混淆器
2006/12/18 Javascript
niceTitle 基于jquery的超链接提示插件
2010/05/31 Javascript
js中的cookie的读写操作示例详解
2014/04/17 Javascript
jquery实现select下拉框美化特效代码分享
2015/08/18 Javascript
跟我学习javascript的var预解析与函数声明提升
2015/11/16 Javascript
javascript中select下拉框的用法总结
2016/01/07 Javascript
利用Jquery实现几款漂亮实用的时间轴(附示例代码)
2017/02/15 Javascript
Node.js安装配置图文教程
2017/05/10 Javascript
javascript兼容性(实例讲解)
2017/08/15 Javascript
解决select2在bootstrap modal中不能正常使用的问题
2018/08/09 Javascript
vue项目中使用Svg的方法
2018/10/24 Javascript
js实现通过开始结束控制的计时器
2019/02/25 Javascript
今天,小程序正式支持 SVG
2019/04/20 Javascript
js图片无缝滚动插件使用详解
2020/05/26 Javascript
基于better-scroll 实现歌词联动功能的代码
2020/05/07 Javascript
Python中map和列表推导效率比较实例分析
2015/06/17 Python
Python实现各种排序算法的代码示例总结
2015/12/11 Python
python 截取 取出一部分的字符串方法
2017/03/01 Python
python  Django中的apps.py的目的是什么
2018/10/15 Python
python画图--输出指定像素点的颜色值方法
2019/07/03 Python
浅谈pytorch池化maxpool2D注意事项
2020/02/18 Python
Python递归求出列表(包括列表中的子列表)的最大值实例
2020/02/27 Python
Keras—embedding嵌入层的用法详解
2020/06/10 Python
django美化后台django-suit的安装配置操作
2020/07/12 Python
CSS3实现全景图特效示例代码
2018/03/26 HTML / CSS
购房协议书范本
2014/04/11 职场文书
公司运动会策划方案
2014/05/25 职场文书
2014年出纳工作总结与计划
2014/12/09 职场文书
教师个人学习总结
2015/02/11 职场文书
女方家长婚礼致辞
2015/07/27 职场文书
合同补充协议书
2016/03/24 职场文书
javaScript Array api梳理
2021/03/31 Javascript
python 如何用terminal输入参数
2021/05/25 Python
详细聊一聊mysql的树形结构存储以及查询
2022/04/05 MySQL