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 相关文章推荐
用javascript实现页面打印的三种方法
Mar 05 Javascript
jQuery判断checkbox是否选中的小例子
Dec 02 Javascript
解析jquery中的ajax缓存问题
Dec 19 Javascript
javascript跨域的4种方法和原理详解
Apr 08 Javascript
jQuery 回调函数(callback)的使用和基础
Feb 26 Javascript
jQuery Validate表单验证插件 添加class属性形式的校验
Jan 18 Javascript
Bootstrap每天必学之弹出框(Popover)插件
Apr 25 Javascript
JS两个数组比较,删除重复值的巧妙方法(推荐)
Jun 03 Javascript
微信小程序 保留小数(toFixed)详细介绍
Nov 16 Javascript
jQuery基于xml格式数据实现模糊查询及分页功能的方法
Dec 25 Javascript
原生js实现网页顶部自动下拉/收缩广告效果
Jan 20 Javascript
使用Karma做vue组件单元测试的实现
Jan 16 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/11/19 PHP
PHP 抓取网页图片并且另存为的实现代码
2010/03/24 PHP
PHP MemCached高级缓存配置图文教程
2010/08/05 PHP
js 动态选中下拉框
2009/11/26 Javascript
用js实现计算加载页面所用的时间
2010/04/02 Javascript
JavaScript下利用fso判断文件是否存在的代码
2010/12/11 Javascript
使用简洁的jQuery方法实现隔行换色功能
2014/01/02 Javascript
JS实现在页面随时自定义背景颜色的方法
2015/02/27 Javascript
JS表格组件神器bootstrap table详解(基础版)
2015/12/08 Javascript
jQuery简单操作cookie的插件实例
2016/01/13 Javascript
基于javascript实现九宫格大转盘效果
2020/05/28 Javascript
Node.js实现数据推送
2016/04/14 Javascript
如何使用jquery修改css中带有!important的样式属性
2016/04/28 Javascript
jQuery实现元素的插入
2017/02/27 Javascript
浅谈VUE监听窗口变化事件的问题
2018/02/24 Javascript
更强大的vue ssr实现预取数据的方式
2019/07/19 Javascript
[56:41]2018DOTA2亚洲邀请赛 3.31 小组赛 A组 Newbee vs OG
2018/04/01 DOTA
[57:55]完美世界DOTA2联赛PWL S3 Magma vs Phoenix 第二场 12.12
2020/12/16 DOTA
Python中的lstrip()方法使用简介
2015/05/19 Python
将Python的Django框架与认证系统整合的方法
2015/07/24 Python
Python3实现爬取指定百度贴吧页面并保存页面数据生成本地文档的方法
2018/04/22 Python
python实现内存监控系统
2021/03/07 Python
如何安装多版本python python2和python3共存以及pip共存
2018/09/18 Python
对python特殊函数 __call__()的使用详解
2019/07/02 Python
关于numpy.where()函数 返回值的解释
2019/12/06 Python
python实现梯度下降和逻辑回归
2020/03/24 Python
基于Python爬取股票数据过程详解
2020/10/21 Python
HTML5中的新元素介绍
2008/10/17 HTML / CSS
amazeui 验证按钮扩展的实现
2020/08/21 HTML / CSS
仓库管理专业个人自我评价范文
2013/11/11 职场文书
《赶海》教学反思
2014/04/20 职场文书
课前三分钟演讲稿
2014/04/24 职场文书
如何写早恋检讨书
2014/09/10 职场文书
Django rest framework如何自定义用户表
2021/06/09 Python
swagger如何返回map字段注释
2021/07/03 Java/Android
mysql 排序失效
2022/05/20 MySQL