javascript中的缓动效果实现程序


Posted in Javascript onDecember 29, 2012

常见的动画有四种类型,介绍一下:

linear:线性动画,即匀速

easeIn:速度从小到大,即淡入

easeOut :速度从大到小,即淡出

easeInOut:开始时速度从小到大,结束时速度从大到小,即淡入淡出

其实说到缓动,就不得不提Robert Penner,他发明了N多缓动公式,举个例子

我还是解释一下吧:

设当前变化量为X,则

t / d = X / c,所以X = c * t / d,然后X + b就可以获得当前属性值

再看一个稍复杂的:
 
这个有淡入效果,也就是说动画开始时,值的变化量从小到大。
可以发现两者唯一的区别就是 t / d 和 (t /= d) * t,刚才说了t / d是一个>=0 && <=1的比值,暂取名为a,而(t /= d) * t就相当于Math.pow(a, 2)。

为什么要平方呢?

1. 首先a >= Math.pow(a, 2)是肯定的
2. 每次调用函数时,t / d 这个比值也是匀速变大的,比如第1次调用时是0.1(平方0.01),第2次调用时是0.2(平方0.04)等,那第10次调用时,肯定是1没错吧,这时候 c * 1 + b,动画就到此结束了
3. 第2点证明了比值越小,值的变化量就越小,比值越大,值的变化量就越大,如果不用平方而是三次方,那淡入效果就更明显了。

样式、结构及公共函数如下:

 <style>
        #container {width:500px;height:100px;border:1px #d1d1d1 solid;position:relative;}
        #drag {width:100px;height:100px;background:#369;position:absolute;left:0;top:0;}
    </style>
<div id="container">
<div id="drag"></div>
</div>    <script type="text/javascript">
        function $(id) {
            return typeof id == 'string' ? document.getElementById(id) : id;
        }
        function getStyle(el,styleProp){
            return el.currentStyle ? el.currentStyle[styleProp] : document.defaultView.getComputedStyle(el,null).getPropertyValue(styleProp);
        }
    </script>

首先,从最简单的入手:设定开始位置和结束位置及步长,每次增加固定的值,直至终止条件
var timer = null;
        var begin = 0, end = 400, step = 5;
        var drag = $("drag");
        function run() {
            if((iLeft = parseInt(getStyle(drag,"left"))) < end){
                drag.style.left = iLeft + step + "px";
            }else{
                clearInterval(timer);
            }
        }
        var timer = setInterval(run, 20);

上面这种方法是匀速,每次运动的距离是固定的,下面来看另外一种实现方式:
 var timer = null;
        var begin = 0, end = 400;
        var drag = $("drag");
        function run() {
            if((iLeft = parseInt(getStyle(drag,"left"))) < end){
                var step = Math.ceil((400 - iLeft)/7);
                drag.style.left = iLeft + step + "px";
            }else{
                clearInterval(timer);
            }
        }
        var timer = setInterval(run, 20);

上面这种方式是通过当前的位置距离目标的距离来计算此次位移的步长
在flash中有专门处理缓动的类tween,转化为javascript的代码为:

var Tween = {
 Linear: function(t,b,c,d){ return c*t/d + b; },
 Quad: {
  easeIn: function(t,b,c,d){
   return c*(t/=d)*t + b;
  },
  easeOut: function(t,b,c,d){
   return -c *(t/=d)*(t-2) + b;
  },
  easeInOut: function(t,b,c,d){
   if ((t/=d/2) < 1) return c/2*t*t + b;
   return -c/2 * ((--t)*(t-2) - 1) + b;
  }
 },
 Cubic: {
  easeIn: function(t,b,c,d){
   return c*(t/=d)*t*t + b;
  },
  easeOut: function(t,b,c,d){
   return c*((t=t/d-1)*t*t + 1) + b;
  },
  easeInOut: function(t,b,c,d){
   if ((t/=d/2) < 1) return c/2*t*t*t + b;
   return c/2*((t-=2)*t*t + 2) + b;
  }
 },
 Quart: {
  easeIn: function(t,b,c,d){
   return c*(t/=d)*t*t*t + b;
  },
  easeOut: function(t,b,c,d){
   return -c * ((t=t/d-1)*t*t*t - 1) + b;
  },
  easeInOut: function(t,b,c,d){
   if ((t/=d/2) < 1) return c/2*t*t*t*t + b;
   return -c/2 * ((t-=2)*t*t*t - 2) + b;
  }
 },
 Quint: {
  easeIn: function(t,b,c,d){
   return c*(t/=d)*t*t*t*t + b;
  },
  easeOut: function(t,b,c,d){
   return c*((t=t/d-1)*t*t*t*t + 1) + b;
  },
  easeInOut: function(t,b,c,d){
   if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b;
   return c/2*((t-=2)*t*t*t*t + 2) + b;
  }
 },
 Sine: {
  easeIn: function(t,b,c,d){
   return -c * Math.cos(t/d * (Math.PI/2)) + c + b;
  },
  easeOut: function(t,b,c,d){
   return c * Math.sin(t/d * (Math.PI/2)) + b;
  },
  easeInOut: function(t,b,c,d){
   return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;
  }
 },
 Expo: {
  easeIn: function(t,b,c,d){
   return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;
  },
  easeOut: function(t,b,c,d){
   return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
  },
  easeInOut: function(t,b,c,d){
   if (t==0) return b;
   if (t==d) return b+c;
   if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;
   return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
  }
 },
 Circ: {
  easeIn: function(t,b,c,d){
   return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b;
  },
  easeOut: function(t,b,c,d){
   return c * Math.sqrt(1 - (t=t/d-1)*t) + b;
  },
  easeInOut: function(t,b,c,d){
   if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b;
   return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b;
  }
 },
 Elastic: {
  easeIn: function(t,b,c,d,a,p){
   if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;
   if (!a || a < Math.abs(c)) { a=c; var s=p/4; }
   else var s = p/(2*Math.PI) * Math.asin (c/a);
   return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
  },
  easeOut: function(t,b,c,d,a,p){
   if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;
   if (!a || a < Math.abs(c)) { a=c; var s=p/4; }
   else var s = p/(2*Math.PI) * Math.asin (c/a);
   return (a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b);
  },
  easeInOut: function(t,b,c,d,a,p){
   if (t==0) return b;  if ((t/=d/2)==2) return b+c;  if (!p) p=d*(.3*1.5);
   if (!a || a < Math.abs(c)) { a=c; var s=p/4; }
   else var s = p/(2*Math.PI) * Math.asin (c/a);
   if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
   return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b;
  }
 },
 Back: {
  easeIn: function(t,b,c,d,s){
   if (s == undefined) s = 1.70158;
   return c*(t/=d)*t*((s+1)*t - s) + b;
  },
  easeOut: function(t,b,c,d,s){
   if (s == undefined) s = 1.70158;
   return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
  },
  easeInOut: function(t,b,c,d,s){
   if (s == undefined) s = 1.70158;
   if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
   return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
  }
 },
 Bounce: {
  easeIn: function(t,b,c,d){
   return c - Tween.Bounce.easeOut(d-t, 0, c, d) + b;
  },
  easeOut: function(t,b,c,d){
   if ((t/=d) < (1/2.75)) {
    return c*(7.5625*t*t) + b;
   } else if (t < (2/2.75)) {
    return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
   } else if (t < (2.5/2.75)) {
    return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
   } else {
    return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
   }
  },
  easeInOut: function(t,b,c,d){
   if (t < d/2) return Tween.Bounce.easeIn(t*2, 0, c, d) * .5 + b;
   else return Tween.Bounce.easeOut(t*2-d, 0, c, d) * .5 + c*.5 + b;
  }
 }
}

其中每种缓动方式中对应3种类型
easeIn:从0开始加速的缓动;
easeOut:减速到0的缓动;
easeInOut:前半段从0开始加速,后半段减速到0的缓动
参数说明:
t:当前时间
b:初始值
c:变化量
d:持续时间
调用方式:
 var timer = null;
        var b=0,c=400,d=100,t=0;
        var drag = $("drag");
        function run() {
            drag.style.left = Math.ceil(Tween.Circ.easeInOut(t,b,c,d)) + "px";
            if(t<d){
                t++;
            }else{
                clearInterval(timer);
            }
        }
var timer = setInterval(run, 20);
Javascript 相关文章推荐
两个DIV等高的JS的实现代码
Dec 23 Javascript
jQuery过滤选择器经典应用
Aug 18 Javascript
纯JavaScript 实现flappy bird小游戏实例代码
Sep 27 Javascript
js eval函数使用,js对象和字符串互转实例
Mar 06 Javascript
利用Node.js检测端口是否被占用的方法
Dec 07 Javascript
jquery根据name取得select选中的值实例(超简单)
Jan 25 jQuery
支付宝小程序tabbar底部导航
Nov 06 Javascript
JQuery搜索框自动补全(模糊匹配)功能实现示例
Jan 08 jQuery
JavaScript数据结构与算法之二叉树实现查找最小值、最大值、给定值算法示例
Mar 01 Javascript
layer.open弹层查看缩略图的原图,自适应大小的实例
Sep 05 Javascript
微信小程序实现音乐播放器
Nov 20 Javascript
原生js实现ajax请求和JSONP跨域请求操作示例
Mar 14 Javascript
通过正则格式化url查询字符串实现代码
Dec 28 #Javascript
Js数组的操作push,pop,shift,unshift等方法详细介绍
Dec 28 #Javascript
载入jQuery库的最佳方法详细说明及实现代码
Dec 28 #Javascript
一个背景云变换js特效 鼠标移动背景云变化
Dec 28 #Javascript
javascript 实现简单的table排序及table操作练习
Dec 28 #Javascript
jQuery 选择器项目实例分析及实现代码
Dec 28 #Javascript
jQuery插件-jRating评分插件源码分析及使用方法
Dec 28 #Javascript
You might like
PHP 字符串操作入门教程
2006/12/06 PHP
php字符串的替换,分割和连接方法
2016/05/23 PHP
PHP 中 DOMDocument保存xml时中文出现乱码问题的解决方案
2016/09/19 PHP
php变量与JS变量实现不通过跳转直接交互的方法
2017/08/25 PHP
PHP count_chars()函数讲解
2019/02/14 PHP
通过代码实例解析PHP session工作原理
2020/12/11 PHP
angularjs中的单元测试实例
2014/12/06 Javascript
js使用心得分享
2015/01/13 Javascript
javascript为按钮注册回车事件(设置默认按钮)的方法
2015/05/09 Javascript
JavaScript学习笔记之创建对象
2016/03/25 Javascript
Vue 固定头 固定列 点击表头可排序的表格组件
2016/11/25 Javascript
JS双击变input框批量修改内容
2016/12/12 Javascript
jquery插件treegrid树状表格的使用方法详解(.Net平台)
2017/01/03 Javascript
详解如何在NodeJS项目中优雅的使用ES6
2017/04/22 NodeJs
AngularJS 中的数据源的循环输出
2017/10/12 Javascript
理解 JavaScript EventEmitter
2018/03/29 Javascript
Vue在 Nuxt.js 中重定向 404 页面的方法
2019/04/23 Javascript
Python 中 list 的各项操作技巧
2017/04/13 Python
python数字图像处理之高级滤波代码详解
2017/11/23 Python
Python 实现12306登录功能实例代码
2018/02/09 Python
python中的json总结
2018/10/11 Python
python selenium firefox使用详解
2019/02/26 Python
Cole Haan官方网站:美国时尚潮流品牌
2017/12/06 全球购物
英国受欢迎的运动鞋和街头服装商店:Footasylum
2018/06/12 全球购物
Weblogc domain问题
2014/01/27 面试题
*p++ 自增p 还是p所指向的变量
2016/07/16 面试题
定义一结构体数组表示分数,并求两个分数相加之和
2013/06/11 面试题
实习老师离校感言
2014/02/03 职场文书
物流专员岗位职责
2014/02/17 职场文书
小学生开学感言
2014/02/28 职场文书
运输企业安全生产责任书
2014/07/28 职场文书
2014年全国爱牙日宣传活动方案
2014/09/21 职场文书
个人党性分析总结
2015/03/05 职场文书
解除租赁合同协议书
2016/03/21 职场文书
Spring-cloud Config Server的3种配置方式
2021/09/25 Java/Android
Redis三种集群模式详解
2021/10/05 Redis