jQuery.setAuto这个方法实在看不出来到底有啥用,而且到后面的版本就把这个方法去掉了
直接看speed方法
jQuery.extend({ speed: function(s,o) { o = o || {}; if ( o.constructor == Function ) o = { complete: o }; var ss = { slow: 600, fast: 200 }; o.duration = (s && s.constructor == Number ? s : ss[s]) || 400; // Queueing o.oldComplete = o.complete; o.complete = function(){ jQuery.dequeue(this, "fx"); if ( o.oldComplete && o.oldComplete.constructor == Function ) o.oldComplete.apply( this ); }; return o; }});
从名字上看很容易知道这是控制速度的一个方法
从源码中看,在animate方法中通过jQuery.speed(speed,callback)调用了一次
speed方法最终会构造一个json形式的config,结构如下:
{ duration:400,//持续时间 oldComplete:function(){ ...//自定义的函数 }, complete:function(){ jQuery.dequeue(this, "fx"); if ( o.oldComplete && o.oldComplete.constructor == Function ) o.oldComplete.apply( this ); } }
调用complete时里面的this指向一定有变化,所以等分析到调用complete的时候再看
接下来的dequeue方法也一样,从字面上来看就是出队的意思
再往下的fx方法是核心
jQuery.extend( fx: function( elem, options, prop ){ var z = this; z.o = {...}; z.el = elem; z.a = function(){...}; z.max = function(){...}; z.cur = function(){...}; z.custom = function(from,to){...}; z.show = function( p ){...}; z.hide = function(){...}; z.step = function(firstNum, lastNum){...}; } );
实际上,jQuery.fx在源码中被用作构造方法,从animate实力方法中发现通过new jQuery.fx()来调用了
z就是new出来的对象,然后往对象上扩展了很多方法
构造方法里面的各个方法之间相互调用,因此比较复杂,我们通过一个例子来看
$("#div1").animate({"width":500},1000,function(){alert("over");});
意思就是让#div1在1s时间内宽变到500,完了之后弹出over
1、queue
调用形式为this.queue(function(){...});
queue: function(type,fn){ if ( !fn ) { fn = type; type = "fx"; } return this.each(function(){ //此处的this是jQuery对象 if ( !this.queue ) this.queue = {}; if ( !this.queue[type] ) this.queue[type] = []; //以上代码是给jQuery对象里面的每个DOM元素都附加queue这个属性,queue下将会按照队列的类型来存放函数 this.queue[type].push( fn ); //如果当前type类型的队列里面只有一个函数,就直接执行,而且这个函数内部的this更改为了each每次遍历到的DOM对象 if ( this.queue[type].length == 1 ) fn.apply(this); }); }
2、执行传入this.queue里面的函数
animate: function(prop,speed,callback) { return this.queue(function(){ this.curAnim = prop;//this指向queue中遍历到的DOM对象,prop形如 /*{ "width":500, "opacity":50, "height":200 }*/ for ( var p in prop ) { var e = new jQuery.fx( this, jQuery.speed(speed,callback), p ); if ( prop[p].constructor == Number ) //custom的两个参数分别是起始值和目标值 e.custom( e.cur(), prop[p] ); else//暂时搞不太清楚什么时候走else这个分支 e[ prop[p] ]( prop ); } }); },
3、cur custom
//得到elem当前prop的值 z.cur = function(){ var r = parseFloat( jQuery.curCSS(z.el, prop) ); return r && r > -10000 ? r : z.max(); };
//在当前实例化对象上绑定startTime、now属性,now存储的是最初从哪个值开始动,startTime和now这两个属性为接下来执行的a和step做了铺垫 z.custom = function(from,to){ z.startTime = (new Date()).getTime(); z.now = from; z.a(); z.timer = setInterval(function(){ z.step(from, to); }, 13); };
4、a
z.a = function(){ //目前很明显options里面只有complete、oldComplete、duration三个属性,没有step if ( options.step ) options.step.apply( elem, [ z.now ] ); //当改变的样式是透明度时,对于IE浏览器要做特殊处理 if ( prop == "opacity" ) { if (z.now == 1) z.now = 0.9999; if (window.ActiveXObject) y.filter = "alpha(opacity=" + z.now*100 + ")"; else y.opacity = z.now; } else if ( parseInt(z.now) ) //如果运动形式不是opacity,就直接按照数字处理 y[prop] = parseInt(z.now) + "px"; y.display = "block"; };
5、step
这个step方法每隔13毫秒就会调用一次
step先获取当前调用step的时间戳
再判断是否到达了目的值
如果没到目的值,递增或递减z.now的值,并再次执行z.a将递增或递减后的值赋给DOM元素
如果到达目的值了就停掉定时器,然后判断别运动的样式是否到目的值,如果全都到了就再去做一系列后续操作,执行结束的回调函数