浅析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 相关文章推荐
JavaScript对象学习经验整理
Oct 12 Javascript
页面实时更新时间的JS实例代码
Dec 18 Javascript
返回上一页并自动刷新的JavaScript代码
Feb 19 Javascript
ECMAScript5(ES5)中bind方法使用小结
May 07 Javascript
js闭包所用的场合以及优缺点分析
Jun 22 Javascript
AngularJS中如何使用$parse或$eval在运行时对Scope变量赋值
Jan 25 Javascript
Vue之Watcher源码解析(2)
Jul 19 Javascript
jquery如何实现点击空白处隐藏元素
Dec 05 jQuery
解决layer弹出层的内容页点击按钮跳转到新的页面问题
Sep 14 Javascript
Vue中通过属性绑定为元素绑定style行内样式的实例代码
Apr 30 Javascript
在Vue中使用antv的示例代码
Jun 29 Javascript
JS前端宏任务微任务及Event Loop使用详解
Jul 23 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网站来路获取代码(针对搜索引擎)
2010/06/08 PHP
PHP zlib扩展实现页面GZIP压缩输出
2010/06/17 PHP
php封装的验证码类分享
2017/02/26 PHP
PHP PDOStatement::rowCount讲解
2019/02/01 PHP
纯JavaScript实现的完美渐变弹出层效果代码
2010/04/02 Javascript
js 如何实现对数据库的增删改查
2012/11/23 Javascript
文本有关的样式和jQuery求对象的高宽问题分别说明
2013/08/30 Javascript
如何在父窗口中得知window.open()出的子窗口关闭事件
2013/10/15 Javascript
jquery实现的随机多彩tag标签随机颜色和字号大小效果
2014/03/27 Javascript
Javascript中浮点数相乘的一个解决方法
2014/06/03 Javascript
js数组的基本操作(很全自己整理的)
2014/10/16 Javascript
js获取鼠标点击的对象,点击另一个按钮删除该对象的实现代码
2016/05/13 Javascript
KnockoutJS 3.X API 第四章之click绑定
2016/10/10 Javascript
nodejs读写json文件的简单方法(必看)
2017/03/09 NodeJs
vue上传图片组件编写代码
2017/07/26 Javascript
JavaScript自执行函数和jQuery扩展方法详解
2017/10/27 jQuery
微信小程序scroll-view仿拼多多横向滑动滚动条
2020/04/21 Javascript
详解微信小程序调起键盘性能优化
2018/07/24 Javascript
vue2.0+vue-router构建一个简单的列表页的示例代码
2019/02/13 Javascript
Vue CLI3.0中使用jQuery和Bootstrap的方法
2019/02/28 jQuery
微信小程序仿淘宝热搜词在搜索框中轮播功能
2020/01/21 Javascript
vue elementui tree 任意级别拖拽功能代码
2020/08/31 Javascript
Vue中使用wangeditor富文本编辑的问题
2021/02/07 Vue.js
Python的Scrapy爬虫框架简单学习笔记
2016/01/20 Python
Python基于列表模拟堆栈和队列功能示例
2018/01/05 Python
Python实现通过解析域名获取ip地址的方法分析
2019/05/17 Python
python中用logging实现日志滚动和过期日志删除功能
2019/08/20 Python
Python安装及Pycharm安装使用教程图解
2019/09/20 Python
如何在windows下安装配置python工具Ulipad
2020/10/27 Python
计算机系毕业生推荐信
2013/11/06 职场文书
校园文化艺术节宣传标语
2014/10/09 职场文书
大学生上课迟到检讨书
2014/10/15 职场文书
金正昆讲礼仪观后感
2015/06/11 职场文书
单位工资证明范本
2015/06/12 职场文书
pytorch查看网络参数显存占用量等操作
2021/05/12 Python
Python学习之os包使用教程详解
2022/03/21 Python