浅析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 相关文章推荐
Prototype使用指南之selector.js
Jan 10 Javascript
jQuery中animate用法实例分析
Mar 09 Javascript
jquery实现倒计时功能
Dec 28 Javascript
js+html5实现的自由落体运动效果代码
Jan 28 Javascript
BootStrap的Datepicker控件使用心得分享
May 25 Javascript
jquery hover 不停闪动问题的解决方法(亦为stop()的使用)
Feb 10 Javascript
Vuejs 组件——props数据传递的实例代码
Mar 07 Javascript
Vue + better-scroll 实现移动端字母索引导航功能
May 07 Javascript
vue源码学习之Object.defineProperty 对数组监听
May 30 Javascript
JavaScript模拟实现自由落体效果
Aug 28 Javascript
JS实现可用滑块滑动的缓动图代码
Sep 01 Javascript
js实现计时器秒表功能
Dec 16 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
超人钢铁侠联手合作?美漫作家呼吁DC漫威合作联动以抵抗疫情
2020/04/09 欧美动漫
PHP批量上传图片的具体实现方法介绍.
2014/02/26 PHP
PHP常用处理静态操作类
2015/04/03 PHP
关于Anemometer图形化显示MySQL慢日志的工具搭建及使用的详细介绍
2020/07/13 PHP
PHP+MySql实现一个简单的留言板
2020/07/19 PHP
点弹代码 点击页面任何位置都可以弹出页面效果代码
2012/09/17 Javascript
JS测试显示屏分辨率以及屏幕尺寸的方法
2013/11/22 Javascript
jquery实现导航固定顶部的效果仿蘑菇街
2014/10/22 Javascript
node.js中的fs.symlink方法使用说明
2014/12/15 Javascript
javascript通过元素id和name直接取得元素的方法
2015/04/28 Javascript
jQuery实现大转盘抽奖活动仿QQ音乐代码分享
2015/08/21 Javascript
深入浅析JavaScript中的作用域和上下文
2016/03/26 Javascript
仿百度换肤功能的简单实例代码
2016/07/11 Javascript
Angular2表单自定义验证器的实现
2016/10/19 Javascript
vue.js内部自定义指令与全局自定义指令的实现详解(利用directive)
2017/07/11 Javascript
详解webpack进阶之loader篇
2017/08/23 Javascript
利用canvas中toDataURL()将图片转为dataURL(base64)的方法详解
2017/11/20 Javascript
vue cli 全面解析
2018/02/28 Javascript
vue 多入口文件搭建 vue多页面搭建的实例讲解
2018/03/12 Javascript
Vuex持久化插件(vuex-persistedstate)解决刷新数据消失的问题
2019/04/16 Javascript
Vue-cli3.X使用px2 rem遇到的问题及解决方法
2019/08/08 Javascript
基于jquery ajax的多文件上传进度条过程解析
2019/09/11 jQuery
微信小程序webSocket的使用方法
2020/02/20 Javascript
vue 路由meta 设置导航隐藏与显示功能的示例代码
2020/09/04 Javascript
50行Python代码实现人脸检测功能
2018/01/23 Python
Pytoch之torchvision.transforms图像变换实例
2019/12/30 Python
pycharm + django跨域无提示的解决方法
2020/12/06 Python
企业为何需要商业计划书
2013/12/26 职场文书
请假条格式范文
2014/04/10 职场文书
我爱我家教学反思
2014/05/01 职场文书
水污染治理工程专业求职信
2014/06/14 职场文书
2015学习委员工作总结范文
2015/04/03 职场文书
初中重阳节活动总结
2015/05/05 职场文书
幼儿园班级管理心得体会
2016/01/07 职场文书
python实现监听键盘
2021/04/26 Python
Spring Boot 底层原理基础深度解析
2022/04/03 Java/Android