动画

昨天写《锋利的JQ》里的动画案例卡住了,切换都成功了,但没有动画效果,按自己以前学的动画知识,在那里连接不上。不得已继续搜寻资料学习动画。

看了一个“CJ”的javascript视频教程,觉得里面讲的动画挺不错的。有必要记录下。

首先,我们知道,最常见的动画莫过于移动,一般都是通过修改node.style['left' | 'top']这样实现。那么,我们可以构建这么一个小例子,如结构:

<style type="text/css">
    #test{ width:100px; height:100px; background:red; position:absolute; left:100px; top:200px;}
</style>
</head>
<body>
    <div id="test">test</div>
</body>

我们想让它从距左边100个px移动到200px,看JS代码:

window.onload = function(){
       var test = document.getElementById("test");
       test.style.left = test.offsetLeft + 100 + "px";    //offsetLeft获取元素的实际坐标,test.style.left只获取嵌入在html里的样式,而且带单位,如"px"
 }

上面是动了,但是就像”瞬移“一样,直达目的地,这样不好,我们不止要让它动,还要让它动得好看点。

我们知道setInterval可以让我们循环执行,那么,就有了下面代码:

window.onload = function(){
       var test = document.getElementById("test");
       var interval = setInterval(function(){
           if(test.offsetLeft >= 200){
               clearInterval(interval);         //当条件满足时,清除setInterval
               return;
           }
           test.style.left = test.offsetLeft + 1 + "px";  //每次递增1像素
       },50)
}

这样,效果就慢慢的移像我们指定的位置了。

这里,通过运行代码后可以发现,这是慢慢移动了,但是匀速运动,看起来也不是那么好看,我们需要让他在规定时间内,就移动到我们所在的位置。

为了实现要求,网上有这么一个算法库,就是实现动画的不同效果的,如下:

var Tween = {
	Linear:function (start,alter,curTime,dur) {return start+curTime/dur*alter;},//最简单的线性变化,即匀速运动
	Quad:{//二次方缓动
		easeIn:function (start,alter,curTime,dur) {
			return start+Math.pow(curTime/dur,2)*alter;
		},
		easeOut:function (start,alter,curTime,dur) {
			var progress =curTime/dur;
			return start-(Math.pow(progress,2)-2*progress)*alter;
		},
		easeInOut:function (start,alter,curTime,dur) {
			var progress =curTime/dur*2;
			return (progress<1?Math.pow(progress,2):-((--progress)*(progress-2) - 1))*alter/2+start;
		}
	},
	Cubic:{//三次方缓动
		easeIn:function (start,alter,curTime,dur) {
			return start+Math.pow(curTime/dur,3)*alter;
		},
		easeOut:function (start,alter,curTime,dur) {
			var progress =curTime/dur;
			return start-(Math.pow(progress,3)-Math.pow(progress,2)+1)*alter;
		},
		easeInOut:function (start,alter,curTime,dur) {
			var progress =curTime/dur*2;
			return (progress<1?Math.pow(progress,3):((progress-=2)*Math.pow(progress,2) + 2))*alter/2+start;
		}
	},
	Quart:{//四次方缓动
		easeIn:function (start,alter,curTime,dur) {
			return start+Math.pow(curTime/dur,4)*alter;
		},
		easeOut:function (start,alter,curTime,dur) {
			var progress =curTime/dur;
			return start-(Math.pow(progress,4)-Math.pow(progress,3)-1)*alter;
		},
		easeInOut:function (start,alter,curTime,dur) {
			var progress =curTime/dur*2;
			return (progress<1?Math.pow(progress,4):-((progress-=2)*Math.pow(progress,3) - 2))*alter/2+start;
		}
	},
	Quint:{//五次方缓动
		easeIn:function (start,alter,curTime,dur) {
			return start+Math.pow(curTime/dur,5)*alter;
		},
		easeOut:function (start,alter,curTime,dur) {
			var progress =curTime/dur;
			return start-(Math.pow(progress,5)-Math.pow(progress,4)+1)*alter;
		},
		easeInOut:function (start,alter,curTime,dur) {
			var progress =curTime/dur*2;
			return (progress<1?Math.pow(progress,5):((progress-=2)*Math.pow(progress,4) +2))*alter/2+start;
		}
	},
	Sine :{//正弦曲线缓动
		easeIn:function (start,alter,curTime,dur) {
			return start-(Math.cos(curTime/dur*Math.PI/2)-1)*alter;
		},
		easeOut:function (start,alter,curTime,dur) {
			return start+Math.sin(curTime/dur*Math.PI/2)*alter;
		},
		easeInOut:function (start,alter,curTime,dur) {
			return start-(Math.cos(curTime/dur*Math.PI/2)-1)*alter/2;
		}
	},
	Expo: {//指数曲线缓动
		easeIn:function (start,alter,curTime,dur) {
			return curTime?(start+alter*Math.pow(2,10*(curTime/dur-1))):start;
		},
		easeOut:function (start,alter,curTime,dur) {
			return (curTime==dur)?(start+alter):(start-(Math.pow(2,-10*curTime/dur)+1)*alter);
		},
		easeInOut:function (start,alter,curTime,dur) {
			if (!curTime) {return start;}
			if (curTime==dur) {return start+alter;}
			var progress =curTime/dur*2;
			if (progress < 1) {
				return alter/2*Math.pow(2,10* (progress-1))+start;
			} else {
				return alter/2* (-Math.pow(2, -10*--progress) + 2) +start;
			}
		}
	},
	Circ :{//圆形曲线缓动
		easeIn:function (start,alter,curTime,dur) {
			return start-alter*Math.sqrt(-Math.pow(curTime/dur,2));
		},
		easeOut:function (start,alter,curTime,dur) {
			return start+alter*Math.sqrt(1-Math.pow(curTime/dur-1));
		},
		easeInOut:function (start,alter,curTime,dur) {
			var progress =curTime/dur*2;
			return (progress<1?1-Math.sqrt(1-Math.pow(progress,2)):(Math.sqrt(1 - Math.pow(progress-2,2)) + 1))*alter/2+start;
		}
	},
	Elastic: {//指数衰减的正弦曲线缓动
		easeIn:function (start,alter,curTime,dur,extent,cycle) {
			if (!curTime) {return start;}
			if ((curTime==dur)==1) {return start+alter;}
			if (!cycle) {cycle=dur*0.3;}
			var s;
			if (!extent || extent< Math.abs(alter)) {
				extent=alter;
				s = cycle/4;
			} else {s=cycle/(Math.PI*2)*Math.asin(alter/extent);}
			return start-extent*Math.pow(2,10*(curTime/dur-1)) * Math.sin((curTime-dur-s)*(2*Math.PI)/cycle);
		},
		easeOut:function (start,alter,curTime,dur,extent,cycle) {
			if (!curTime) {return start;}
			if (curTime==dur) {return start+alter;}
			if (!cycle) {cycle=dur*0.3;}
			var s;
			if (!extent || extent< Math.abs(alter)) {
				extent=alter;
				s =cycle/4;
			} else {s=cycle/(Math.PI*2)*Math.asin(alter/extent);}
			return start+alter+extent*Math.pow(2,-curTime/dur*10)*Math.sin((curTime-s)*(2*Math.PI)/cycle);
		},
		easeInOut:function (start,alter,curTime,dur,extent,cycle) {
			if (!curTime) {return start;}
			if (curTime==dur) {return start+alter;}
			if (!cycle) {cycle=dur*0.45;}
			var s;
			if (!extent || extent< Math.abs(alter)) {
				extent=alter;
				s =cycle/4;
			} else {s=cycle/(Math.PI*2)*Math.asin(alter/extent);}
			var progress = curTime/dur*2;
			if (progress<1) {
				return start-0.5*extent*Math.pow(2,10*(progress-=1))*Math.sin( (progress*dur-s)*(2*Math.PI)/cycle);
			} else {
				return start+alter+0.5*extent*Math.pow(2,-10*(progress-=1)) * Math.sin( (progress*dur-s)*(2*Math.PI)/cycle);
			}
		}
	},
	Back:{
		easeIn: function (start,alter,curTime,dur,s){
			if (typeof s == "undefined") {s = 1.70158;}
			return start+alter*(curTime/=dur)*curTime*((s+1)*curTime - s);
		},
		easeOut: function (start,alter,curTime,dur,s) {
			if (typeof s == "undefined") {s = 1.70158;}
			return start+alter*((curTime=curTime/dur-1)*curTime*((s+1)*curTime + s) + 1);
		},
		easeInOut: function (start,alter,curTime,dur,s){
			if (typeof s == "undefined") {s = 1.70158;}
			if ((curTime/=dur/2) < 1) {
				return start+alter/2*(Math.pow(curTime,2)*(((s*=(1.525))+1)*curTime- s));
			}
			return start+alter/2*((curTime-=2)*curTime*(((s*=(1.525))+1)*curTime+ s)+2);
		}
	},
	Bounce:{
		easeIn: function(start,alter,curTime,dur){
			return start+alter-Tween.Bounce.easeOut(0,alter,dur-curTime,dur);
		},
		easeOut: function(start,alter,curTime,dur){
			if ((curTime/=dur) < (1/2.75)) {
				return alter*(7.5625*Math.pow(curTime,2))+start;
			} else if (curTime < (2/2.75)) {
				return alter*(7.5625*(curTime-=(1.5/2.75))*curTime + .75)+start;
			} else if (curTime< (2.5/2.75)) {
				return alter*(7.5625*(curTime-=(2.25/2.75))*curTime + .9375)+start;
			} else {
				return alter*(7.5625*(curTime-=(2.625/2.75))*curTime + .984375)+start;
			}
		},
		easeInOut: function (start,alter,curTime,dur){
			if (curTime< dur/2) {
				return Tween.Bounce.easeIn(0,alter,curTime*2,dur) *0.5+start;
			} else {
				return Tween.Bounce.easeOut(0,alter,curTime*2-dur,dur) *0.5 + alter*0.5 +start;
			}
		}
	}
};

这东西看起来很复杂,我们也没必要去深入理解,我们能用即可,现在,我们就将上面的其中一个算法提取出来,并以函数形式展现,如下:

function Quad(start,alter,curTime,dur){
      return start+Math.pow(curTime/dur,2)*alter;
}

这里,start是起始位置,alter是变化量,curTime是当前动画执行的时间,dur是执行的总时间。

我们可以根据这个算法参数再结合我们上面的匀速效果,整合成一个动画函数。这个函数首先要获取动画的对象,起始位置,变化量,执行总时间。而当前动画的执行时间我们可以在运行中获取到,所以此参数可以不用,而Quad的其他参数则都还要。构建好的函数如下:

function animate(obj,start,alter,dur,fx){
       var curTime = 0;    初始时间为0
       var interval = setInterval(function(){
           if(curTime >= dur){           当执行时间等于总时间时,清除动画
               clearInterval(interval);
           }
           for(var i in start){           运用对象方法,可以多次使用
               obj.style[i] = fx(start[i],alter[i],curTime,dur) + "px";
           }
           curTime += 50;
       },50);
}

函数构建好了,看完整代码:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title></title>
<script type="text/javascript" src="jquery-1.4.2.js"></script>
<script type="text/javascript">
   window.onload = function(){
       var test = document.getElementById("test");
       animate(test,{height:100,width:100},{height:200,width:300},1000,Quad);
   }
   function Quad(start,alter,curTime,dur){
      return start+Math.pow(curTime/dur,2)*alter;
   }
   function animate(obj,start,alter,dur,fx){
       var curTime = 0;
       var interval = setInterval(function(){
           if(curTime >= dur){
               clearInterval(interval);
           }
           for(var i in start){
               obj.style[i] = fx(start[i],alter[i],curTime,dur) + "px";
           }
           curTime += 50;
       },50);
   }
</script>
<style type="text/css">
    #test{ width:100px; height:100px; background:red; position:absolute; left:100px; top:200px;}
</style>
</head>
<body>
    <div id="test">test</div>
</body>
</html>
写文章不简单啊,好难叙述,虽然思路就在脑子里,但表达的实在不怎么样,估计这个只有我看得明吧哎。

posted @ 2011-05-06 09:07  肥杜  阅读(266)  评论(0编辑  收藏  举报