jq动画分析1

<!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>
</head>

<style>


#box{
opacity:1;
position: relative;
top:100px;
left: 0px;
300px;
height:300px;
border:1px #ccc solid;
  
  }
#book{
opacity:1;
position:absolute;
top:100px;
left: 100px;
100px;
height:100px;
background: red; 
  }
  
  #book1{
opacity:1;
position:absolute;
top:220px;
left: 0px;
100px;
height:100px;
 background: red; 
  }
.line{
 
position:absolute;
top:0px;
left: 200px;
1px;
height:500px;
 background:#000;
	
	}
</style>
<!--<script src="../jquery-2.2.3.js"></script>-->
 <body>
<button id="one">jQuery动画的模拟实现:放大</button> 
<button id="two">jQuery动画的模拟实现:缩小</button>
 <div id="box"> 
  <div id="book" ></div>
 </div> 
<!-- <div id="book1" ></div>-->
<!-- <div class="line"></div>-->
<script  >
  /*在ie中 consloe.log 如果不在控制台的时候会报错, 调试的时候 按f12 控制台 即可*/

var book = document.getElementById('book');
var book1 = document.getElementById('book1');
var one = document.getElementById('one');
var two = document.getElementById('two');

/*var $book = $('#book');
var i = 10
while(i){
	$book.append("<li>11</li>")
	i--;
}*/


////////////
//创建动画缓动对象 //
////////////
 //生成属性对应的动画算法对象
	// tweens保存每一个属性对应的缓动控制对象
	//properties[k] 值
	// k 是建
	//animation 动画对象
	// 参数为:animation.tweens.push( new Tween(properties[k], k, animation) )
	//Tween 构造函数
	// this.elem 就是用户传进来的dom节点
	//this.prop    = prop; 对象的属性
	//this.easing  = "swing"; //动画缓动算法
	//this.end动画最终值
    //单位 this.unit    = "px"
	//Tween 函数是初始化构造函数
	
function Tween(value, prop, animation) {
	//初始化
	this.elem    = animation.elem;
	this.prop    = prop;
	this.easing  = "swing"; //动画缓动算法
	this.options = animation.options;
	//获取初始值,就是获取动画样式的值, this.get();  
	this.start   = this.now = this.get();
	//动画最终值,就是用户输入的值
	this.end     = value;
	//单位
	this.unit    = "px"
}
//获取动画样式
function getStyles(elem, attr) {
	//return elem.ownerDocument.defaultView.getComputedStyle(elem, null);
	
	if(elem.currentStyle) {
			 // ie   //这样兼容性强
			//console.log('attr='+attr+'||elem.currentStyle[attr]='+elem.currentStyle[attr])  
			 if(elem.currentStyle[attr]=='auto'){
				   elem.style[attr] = '0px';
				 }
 			 return elem.currentStyle[attr];
		} else { 
		    //ff w3c.
		  
		     return getComputedStyle(elem,false)[attr];
		 } 
};

//动画算法
function swing(p) {
	//p 是动画时间比 0 ~ 1
	//Math.cos(x)    x 的余弦值。返回的是 1.0 到 -1.0 之间的数;
	//(p * Math.PI) 是 0到3.14
	//(p * Math.PI)/2  是0到1.57
	//所以   Math.cos(p * Math.PI) / 2   值: 0.5 ~ -05
	//tmpe 值越大跑的越快 
	var tmpe = 0.5 - Math.cos(p * Math.PI) / 2; 
	// tmpe = Math.sin(p*Math.PI/2)
	// console.log('p * Math.PI='+Math.sin(p * Math.PI))
	 //console.log('Math.sin(p * Math.PI)='+ Math.sin(p*Math.PI/2));
	// console.log('Math.cos(p * Math.PI) / 2='+ Math.cos(p * Math.PI) / 2)
 	// console.log('tmpe='+tmpe)
	return tmpe
}


Tween.prototype = {
	//获取元素的当前属性
	get: function() {
		var computed = getStyles(this.elem, this.prop);
		//var ret = computed.getPropertyValue(this.prop) || computed[this.prop];
		//var ret = computed[this.prop];
		//获取样式的值
		//return parseFloat(ret);
		return parseFloat(computed);
	},
	//运行动画
	run:function(percent){
		//percent 动画时间比 0-1
		var eased;
		//根据缓动算法改变percent
		this.pos = eased = swing(percent);
		//获取具体的改变坐标值 this.now缓冲值
		  
		//this.now  (等于结束动画位置 - 开始动画的位置)* 时间戳比例,时间戳比例是从0 ~ 1  this.start 是起始的位置
		this.now = (this.end - this.start) * eased + this.start;
		//console.log('this.now='+this.now)
		 
		//console.log('this.prop='+this.prop+'||this.start='+this.start)
		//最终改变坐标
		//console.log('this.prop='+this.prop+'||this.now='+this.now)
		
		this.elem.style[this.prop] = this.now + "px";
		return this;
	}
}


////////
//动画类 //
////////
//动画对象  elem
 //properties 动画属性
 //options 动画时间  
function Animation(elem, properties, options){
      //检查动画是否在执行	 
	if (Animation.timerId !=undefined && Animation.timerId) {
 		   return false;
		}
	//动画对象
	//animation.elem 动画对象
	//animation.props 动画属性
	//options.options 动画时间
	//Animation.fxNow || createFxNow() 开始动画的时间
	//tweens          : [] //存放每个属性的缓动对象,用于动画
	var animation = {
		elem            : elem,
		props           : properties,
		originalOptions : options,
		options         : options,
		startTime       : null,//动画开始时间
		tweens          : [] //存放每个属性的缓动对象,用于动画
	}

	//生成属性对应的动画算法对象
	// tweens保存每一个属性对应的缓动控制对象
	//properties[k] 值
	// k 是建
	//animation 动画对象
	for (var k in properties) {
	 
		// tweens保存每一个属性对应的缓动控制对象
		animation.tweens.push( new Tween(properties[k], k, animation) )
	}

	//动画状态
	//var stopped;
	//把 animation.startTime=Animation.fxNow || createFxNow(); 放在这里 为了避免 for (var k in properties) for循环的时候如果属性多的时候会出现时间误差,虽然不是很大,但是如果属性很多的话就显得很明显
	animation.startTime=Animation.fxNow || createFxNow();
	//动画的定时器调用包装器  动画循环函数 tick 每13毫秒执行一次
	var tick = function() {
		// console.log(1)
		//如果 stopped 为真则 停止函数
		//if (stopped) {
		//	return false;
		//}
		
		//动画时间算法  每次更新动画的时间戳
		var currentTime = Animation.fxNow || createFxNow();
			//运动时间递减  
			remaining = Math.max(0, animation.startTime + animation.options.duration - currentTime),
			//时间比
			temp = remaining / animation.options.duration || 0,
			//取反时间比
			percent = 1 - temp;

		var index = 0,
			length = animation.tweens.length;

		//执行动画改变
		for (; index < length; index++) {
			//percent改变值
			//animation.tweens[index] 动画的对 象percent 动画时间比 0-1
			// run 就是一个动画执行多少个动画属性
			animation.tweens[index].run(percent);
		}

		//是否继续,还是停止动画  percent <= 1 表示动画已经到达位置了
		if (percent <= 1 && length) {
			 
			return remaining;
			
		} else {
			//停止 动画
			 
			return false;
		}

	}
	tick.elem = elem;
	tick.anim = animation;
   //只是调用一次而已
   //console.log(3333)
	Animation.fx.timer(tick);
}	

//创建 获取时间戳 函数
function createFxNow() {
	setTimeout(function() {
		//给 Animation.fxNow = undefined; 一个空的对象
		Animation.fxNow = undefined;
	});
	//Date.now() 时间戳
	return (Animation.fxNow = Date.now());
}


 

Animation.fx = {
	//开始动画队列  这个函数也是执行一次而已
	timer: function(timer) {
	    
   	    //这里是把函数放到一个数组里面?有何用处
		Animation.timer=timer;
	     
		if (timer()) {  //timer() 只是调用一个而已,就是说有这个动画时候就执行函数 返回一个false 或者是 remaining;
			//开始执行动画 走这里
			Animation.fx.start();
		}  
	},
	//开始循环 这个函数也是执行一次而已
	start: function() {
		if (!Animation.timerId) {
			 
			Animation.timerId = setInterval(Animation.fx.tick, 13);
		}
	},
	//停止循环 停止定时器
	stop:function(){
		clearInterval(Animation.timerId);
		Animation.timerId = null;
		
	},
	//循环的的检测  重点是这里
	tick: function() {
 		var timer,
			i = 0;
         //每次更新时间戳
		 Animation.fxNow = Date.now();
         //console.log(1)
         //如果所有的动画都执行完了就停止这个定时器
		if (!Animation.timer()) {
		    //console.log('Animation.timer()')
		    //console.log(!Animation.timer())
			Animation.fx.stop();
 		}
		//问题出在这里,因为当执行完只有 Animation.fxNow 时间戳变量值还在,所以就产生了bug
		 Animation.fxNow = undefined;
	}
}





 one.onclick=function(){
	 
	Animation(book, {
		 'width': '300',
		 'height':'300',
		 'marginLeft':'-100',
		 'marginTop':'-100'
	}, {
		duration: 1000
	})
	
	
	
	 
	
} 

two.onclick=function() {
	 
	Animation(book, {
		 '100',
		height:'100',
		marginLeft:'0',
		marginTop:'0'
 	}, {
		duration: 1000
	})
} 













 
</script>
</body>
</html>

  

原文地址:https://www.cnblogs.com/hao123456/p/5525973.html