浅析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 相关文章推荐
基于jQuery制作迷你背词汇工具
Jul 27 Javascript
关于js中alert弹出窗口文本换行问题简单详细说明
Dec 11 Javascript
JS检测图片大小的实例
Aug 21 Javascript
javascript模拟post提交隐藏地址栏的参数
Sep 03 Javascript
javascript中setAttribute()函数使用方法及兼容性
Jul 19 Javascript
JavaScript数组对象赋值用法实例
Aug 04 Javascript
教你用javascript实现随机标签云效果_附代码
Mar 16 Javascript
jQuery给div,Span, a ,button, radio 赋值与取值
Jun 24 Javascript
Javascript typeof与instanceof的区别
Oct 18 Javascript
js实现返回顶部效果
Mar 10 Javascript
使用JavaScript实现链表的数据结构的代码
Aug 02 Javascript
详解Vue-Cli 异步加载数据的一些注意点
Aug 12 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下利用header()函数设置浏览器缓存的代码
2010/09/01 PHP
Apache服务器无法使用的解决方法
2013/05/08 PHP
菜鸟javascript基础资料整理3 正则
2010/12/06 Javascript
jQuery .tmpl(), .template()学习资料小结
2011/07/18 Javascript
输入自动提示搜索提示功能的javascript:sugggestion.js
2013/09/02 Javascript
javascript放大镜效果的简单实现
2013/12/09 Javascript
JS实现控制表格只显示行边框或者只显示列边框的方法
2015/03/31 Javascript
jQuery的animate函数实现图文切换动画效果
2015/05/03 Javascript
js实现div层缓慢收缩与展开的方法
2015/05/11 Javascript
jQuery实现下拉框功能实例代码
2016/05/06 Javascript
JavaScript操作 url 中 search 部分方法函数
2016/06/15 Javascript
js编写一个简单的产品放大效果代码
2016/06/27 Javascript
关于JavaScript 原型链的一点个人理解
2016/07/31 Javascript
详解NodeJs支付宝移动支付签名及验签
2017/01/06 NodeJs
浅谈ECMAScript6新特性之let、const
2017/08/02 Javascript
vue项目中使用axios上传图片等文件操作
2017/11/02 Javascript
vue视频播放暂停代码
2019/11/08 Javascript
Vue实现星级评价效果实例详解
2019/12/30 Javascript
JS数组方法shift()、unshift()用法实例分析
2020/01/18 Javascript
Python实现将数据库一键导出为Excel表格的实例
2016/12/30 Python
Python基于jieba库进行简单分词及词云功能实现方法
2018/06/16 Python
python在openstreetmap地图上绘制路线图的实现
2019/07/11 Python
selenium+python实现自动登陆QQ邮箱并发送邮件功能
2019/12/13 Python
Tensorflow 实现释放内存
2020/02/03 Python
解决windows下python3使用multiprocessing.Pool出现的问题
2020/04/08 Python
python批量生成条形码的示例
2020/10/10 Python
FitFlop美国官网:英国符合人体工学的鞋类品牌
2018/10/05 全球购物
List, Set, Map是否继承自Collection接口?
2016/05/16 面试题
sleep()方法和wait()方法的区别是什么
2012/11/17 面试题
新入职员工的自我介绍演讲稿
2014/01/02 职场文书
小学生获奖感言范文
2014/02/02 职场文书
国际经济贸易专业自荐信
2014/06/13 职场文书
学习十八大的心得体会
2014/09/01 职场文书
高中家长意见怎么写
2015/06/03 职场文书
使用canvas实现雪花飘动效果的示例代码
2021/03/30 HTML / CSS
MySQL8.0的WITH查询详情
2021/08/30 MySQL