天天看點

jquery fx分析

引用:http://www.cnblogs.com/rooney/archive/2008/12/03/1346475.html

1. 8.1 FX的常用方法

2. 和前面分析的代碼相比,FX是非常讓人興奮的。以前javaeye登陸的時候,對其登陸視窗的淡出淡入的特效總是想入非非。 Jquery的core包中也提供了Fx的實作。

3. Fx的實質是連續有序改變dom元素的屬性達到視覺上的效果,動态地變化起來。這些屬性主要是高度,寬度,透明度和顔色(背景色和前景色)等。連續有序是和時間相關的,也就是先在某個時間點改變一下CSS的樣式屬性,下一個時間點再改變一下樣式屬性,達到漸變的過程的效果。

4.

5. Jquery為我們提供了幾種常用的FX的函數。

6. Slide是滑出的動作,對于slide,jquery提供了slideDown、slideUp、slideToggle 三種方法。slideDown是元素向下面漸漸地滑出,最後全部可見。slideUp是元素向上面漸漸地鑽進去,最後不見。slideToggle則是這兩者之間的轉換了。

7. Fade是淡變的動作。對于Fade,jquery提供了fadeIn、fadeOut兩個方法。fadeIn是從無到有漸漸地顯示出整個元素。fadeOut相反,它從有到無漸漸地消失這個元素,fade還提供了一個fadeTo用來改變透明性漸變到一個指定的值,而不是消失。

8. Jquery還提供一組更強大的方法。Show、hide、toggle采用一種更為優美的方式顯示元素。Show是元素的寬度漸漸變成,同時高度也漸漸變大,同時透明度也漸漸從無到不透明。這種的效果是元素從一個點漸漸變大,最終完全地顯示出來。Hide剛是相反,它是漸漸透明同時寬高逐漸變小,最後消失。Toggle是兩者之間的轉換。

9.

10. jQuery.each({

11. slideDown: { height:"show" },

12. slideUp: { height: "hide" },

13. slideToggle: { height: "toggle" },

14. fadeIn: { opacity: "show" },

15. fadeOut: { opacity: "hide" }

16. }, function( name, props ){

17. jQuery.fn[ name ] = function( speed, callback ){

18. return this.animate( props, speed, callback );

19. };

20. });

21. // 把所有比對元素的不透明度以漸進方式調整到指定的不透明度,

22. //并在動畫完成後可選地觸發一個回調函數。這個動畫隻調整元素的不透明度。

23. fadeTo: function(speed,to,callback){

24. return this.animate({opacity: to}, speed, callback);

25. },

26. Slide和fade是通過分别改變height或opacity來完成效果的。其完成的工作任務在this.animate( props, speed, callback ) 上。

27. show

28. 對于show和hide的,它們的效果更好一點,其代碼也複雜一點。

29. // show(speed,[callback])

30. // 以優雅的動畫隐藏所有比對的元素,并在顯示完成後可選地觸發一個回調函數。

31. // 可以根據指定的速度動态地改變每個比對元素的高度、寬度和不透明度。

32. // 顯示隐藏的比對元素 show()

33. show: function(speed,callback){

34. return speed ?

35. this.animate({height: "show", width: "show", opacity: "show"

36. }, speed, callback)

37. : this.filter(":hidden").each(function(){

38. this.style.display = this.oldblock || "";

39. if ( jQuery.css(this,"display") == "none" ) {

40. var elem = jQuery("<" + this.tagName + " />").appendTo("body");

41. this.style.display = elem.css("display");// 預設的顯示的display

42. if (this.style.display == "none")// 顯式地設定該tag不顯示 this.style.display = "block";

43. elem.remove();// 上面這些的處理有沒有必要呢?

44. }

45. }).end();// 回到前一個jQuery對象

46. },

47. hide: function(speed,callback){

48. return speed ?

49. this.animate({height: "hide", width: "hide", opacity: "hide"

50. }, speed, callback)

51. : this.filter(":visible").each(function(){

52. this.oldblock = this.oldblock || jQuery.css(this,"display");

53. this.style.display = "none";

54. }).end();

55. },

56. toggle: function( fn, fn2 ){

57. return jQuery.isFunction(fn) && jQuery.isFunction(fn2) ?

58. this._toggle.apply( this, arguments ) :// 原來的toggle

59. (fn ? this.animate({height: "toggle", width: "toggle",

60. opacity: "toggle"}, fn, fn2)

61. : this.each(function(){jQuery(this)[ jQuery(this).is(":hidden") ?

62. "show" : "hide" ]();}

63. // 對每個元素都調用show,或hide函數。

64. )

65. );

66. },

67. show和hide的函數如果沒有指定speed的參數,它們就直接地show或hide元素。沒有動畫的效果。如果給定的speed的參數。它能根據這個speed的值動态去改變高度寬度透明度來達到動畫的show或hide的效果。Toggle則是這兩樣的變換。

68. prk/彭仁夔 轉載請注明出處 <A href="http://jljlpch.iteye.com/" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" >http://jljlpch.iteye.com/</A>

prk/彭仁夔 轉載請注明出處 http://jljlpch.iteye.com/

8.1 FX的常用方法

和前面分析的代碼相比,FX是非常讓人興奮的。以前javaeye登陸的時候,對其登陸視窗的淡出淡入的特效總是想入非非。Jquery的core包中也提供了Fx的實作。

Fx的實質是連續有序改變dom元素的屬性達到視覺上的效果,動态地變化起來。這些屬性主要是高度,寬度,透明度和顔色(背景色和前景色)等。連續有序是和時間相關的,也就是先在某個時間點改變一下CSS的樣式屬性,下一個時間點再改變一下樣式屬性,達到漸變的過程的效果。

Jquery為我們提供了幾種常用的FX的函數。

Slide是滑出的動作,對于slide,jquery提供了slideDown、slideUp、slideToggle三種方法。slideDown是元素向下面漸漸地滑出,最後全部可見。slideUp是元素向上面漸漸地鑽進去,最後不見。slideToggle則是這兩者之間的轉換了。

Fade是淡變的動作。對于Fade,jquery提供了fadeIn、fadeOut兩個方法。fadeIn是從無到有漸漸地顯示出整個元素。fadeOut相反,它從有到無漸漸地消失這個元素,fade還提供了一個fadeTo用來改變透明性漸變到一個指定的值,而不是消失。

Jquery還提供一組更強大的方法。Show、hide、toggle采用一種更為優美的方式顯示元素。Show是元素的寬度漸漸變成,同時高度也漸漸變大,同時透明度也漸漸從無到不透明。這種的效果是元素從一個點漸漸變大,最終完全地顯示出來。Hide剛是相反,它是漸漸透明同時寬高逐漸變小,最後消失。Toggle是兩者之間的轉換。

jQuery.each({

slideDown: { height:"show" },

slideUp: { height: "hide" },

slideToggle: { height: "toggle" },

fadeIn: { opacity: "show" },

fadeOut: { opacity: "hide" }

}, function( name, props ){

jQuery.fn[ name ] = function( speed, callback ){

return this.animate( props, speed, callback );

};

});

// 把所有比對元素的不透明度以漸進方式調整到指定的不透明度,

//并在動畫完成後可選地觸發一個回調函數。這個動畫隻調整元素的不透明度。

fadeTo: function(speed,to,callback){

return this.animate({opacity: to}, speed, callback);

},

Slide和fade是通過分别改變height或opacity來完成效果的。其完成的工作任務在this.animate( props, speed, callback )上。

show

對于show和hide的,它們的效果更好一點,其代碼也複雜一點。

// show(speed,[callback])

// 以優雅的動畫隐藏所有比對的元素,并在顯示完成後可選地觸發一個回調函數。

// 可以根據指定的速度動态地改變每個比對元素的高度、寬度和不透明度。

// 顯示隐藏的比對元素 show()

show: function(speed,callback){

return speed ?

this.animate({height: "show", width: "show", opacity: "show"

}, speed, callback)

: this.filter(":hidden").each(function(){

this.style.display = this.oldblock || "";

if ( jQuery.css(this,"display") == "none" ) {

var elem = jQuery("<" + this.tagName + " />").appendTo("body");

this.style.display = elem.css("display");// 預設的顯示的display

if (this.style.display == "none")// 顯式地設定該tag不顯示 this.style.display = "block";

elem.remove();// 上面這些的處理有沒有必要呢?

}

}).end();// 回到前一個jQuery對象

},

hide: function(speed,callback){

return speed ?

this.animate({height: "hide", width: "hide", opacity: "hide"

}, speed, callback)

: this.filter(":visible").each(function(){

this.oldblock = this.oldblock || jQuery.css(this,"display");

this.style.display = "none";

}).end();

},

toggle: function( fn, fn2 ){

return jQuery.isFunction(fn) && jQuery.isFunction(fn2) ?

this._toggle.apply( this, arguments ) :// 原來的toggle

(fn ? this.animate({height: "toggle", width: "toggle",

opacity: "toggle"}, fn, fn2)

: this.each(function(){jQuery(this)[ jQuery(this).is(":hidden") ?

"show" : "hide" ]();}

// 對每個元素都調用show,或hide函數。

)

);

},

show和hide的函數如果沒有指定speed的參數,它們就直接地show或hide元素。沒有動畫的效果。如果給定的speed的參數。它能根據這個speed的值動态去改變高度寬度透明度來達到動畫的show或hide的效果。Toggle則是這兩樣的變換。

prk/彭仁夔 轉載請注明出處 http://jljlpch.iteye.com/

Java代碼 複制代碼

1. 8.2 Fx 的核心源碼分析

2. 上面的幾個常用方式都是調用了this.animate。jquery對象的animate是大包大攬的函數。所有的FX的效果都可以從這裡得到。因為FX特效就是通過連續(間隔很小的時間點)去改變元素的CSS的樣式。達到視覺上的效果。 Animate就是根據指定的參數(如speed,元素的屬性的變化範圍)來完成這樣的功能。

3. Animate

4.

17. animate: function( prop, speed, easing, callback ) {

18. var optall = jQuery.speed(speed, easing, callback); ①

19. // 執行each或queue方法

20. return this[ optall.queue === false ? "each" : "queue" ](function(){② var opt = jQuery.extend({}, optall), p,

21. hidden=this.nodeType==1&&jQuery(this).is(":hidden"),//元素節點且隐藏

22. self = this;// 目前的元素

23. for ( p in prop ) { ③

24. // 如果是完成的狀态,就直接調用complate函數

25. if ( prop[p] == "hide" && hidden || prop[p] == "show" && !hidden ) return opt.complete.call(this);

26. if (( p == "height" || p == "width")&& this.style ){//style高寬度

27. opt.display = jQuery.css(this, "display");// 儲存目前元素的display

28. opt.overflow = this.style.overflow;// 保證沒有暗中進行的

29. }

30. }

31. if ( opt.overflow != null )// 超出部分不見

32. this.style.overflow = "hidden";

33. opt.curAnim = jQuery.extend({}, prop);//clone傳入的參數prop

34. jQuery.each( prop, function(name, val){ ④

35. // 對目前元素的給定的屬性進行變化的操作

36. var e = new jQuery.fx( self, opt, name ); ⑤

37. // 傳參的屬性可以用 toggle,show,hide,其它

38. // 調用目前e.show,e.hide,e.val的方法,jQuery.fx.prototype

39. if ( /toggle|show|hide/.test(val) ) ⑥

40. e[ val == "toggle" ? hidden ? "show" : "hide" : val ]( prop ); else { ⑦

41. var parts = al.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/),

42. start = e.cur(true) || 0;// 目前元素目前屬性的值

43. // +=" 或 "-=" 來讓元素做相對運動。

44. if ( parts ) { ⑧

45. var end = parseFloat(parts[2]), unit = parts[3] || "px"; if ( unit != "px" ) {// 計算開始的值=(end/cur)*start

46. self.style[ name ] = (end || 1) + unit;

47. start = ((end || 1) / e.cur(true)) * start;

48. self.style[ name ] = start + unit;

49. }

50. if( parts[1]) end = ((parts[1] == "-="? -1 : 1)* end)+ start;

51. e.custom( start, end, unit );// 動畫

52. }

53. //直接計算start和 end的位置來動畫。val是數值的end,start目前的屬性值。

54. else e.custom( start, val, "" );// 動畫 ⑨

55. }

56. });

57. / For JS strict compliance

58. return true;

59. }); },

60.

61. Animate通過傳入的參數對于jquery對象中的每個元素的每個訓示的屬性都進行時間上漸變的改變。下面就分析其中的代碼。

62. jQuery.speed

63. 在①是就通過jquery.speed來進行參數的統一整理。

64. // 主要用于輔助性的工作

65. speed: function(speed, easing, fn) {

66. var opt = speed && speed.constructor == Object ? speed : {

67. // coplete是至多三個參數的最後一個。看看是否傳入動畫完成回調的函數

68. complete: fn ||!fn && easing ||jQuery.isFunction( speed ) && speed,

69. duration: speed,// 持繼的時間,動畫運作的時間。

70. //找到動畫中屬性随時間漸變的的算法。

71. easing:fn&&easing || easing && easing.constructor != Function && easing

72. };

73. //計算出正确的duration,它支援 fast,slow這樣已經定義的常量

74. opt.duration = (opt.duration &&

75. (opt.duration.constructor == Number?

76. opt.duration :

77. jQuery.fx.speeds[opt.duration]))||jQuery.fx.speeds._default;

78. // Queueing

79. opt.old = opt.complete;

80. //這裡是把complete形成了包裹,看看參數中是否指定隊列操作,

81. //如果先出列,再執行complete

82. opt.complete = function(){

83. //可能通過參數指定queue,this 指向是目前的dom元素。

84. if ( opt.queue !== false ) jQuery(this).dequeue();//出queue

85. if (jQuery.isFunction( opt.old )) opt.old.call( this );

86. };

87.

88. return opt;

89. },

90. jquery.speed是對參數進行管理的操作函數。它首先看看speed是不是緊縮型的參數如 { complete:xx, easing:xx, duration:xx}。如果不是,就根據傳入的參數進行判斷,組成緊縮型的對象參數。

91. 由于jquery對象支援fast,slow這樣的常量來代替具體的speed的數值,第二步就是進行speed的處理。如果沒有提供就提供預設的speed。其代碼在jQuery.fx.speeds中speeds:{ slow: 600, fast: 200, _default: 400},定義了三種形式的速度。

92. 接下來是對在完成的時間執行的complete的回調函數進行包裹。包裹就是看看參數中提供了隊列的操作沒有。提供了就進行出隊列的操作。之後再執行complete的回調函數。

93. jQuery.fn.dequeue = function(type){

94. type = type || "fx";

95. return this.each(function(){

96. var q = queue(this, type);// 得取type的的值

97. q.shift();// 移出一個

98. if ( q.length )

99. q[0].call( this );

100. });

101. };

102. jQuery.fn.dequeue根據type取到目前dom元素的queue。先移出一個。再運作queue中的第一個。

103. Queue

8.2 Fx的核心源碼分析

上面的幾個常用方式都是調用了this.animate。jquery對象的animate是大包大攬的函數。所有的FX的效果都可以從這裡得到。因為FX特效就是通過連續(間隔很小的時間點)去改變元素的CSS的樣式。達到視覺上的效果。Animate就是根據指定的參數(如speed,元素的屬性的變化範圍)來完成這樣的功能。

Animate

animate: function( prop, speed, easing, callback ) {

var optall = jQuery.speed(speed, easing, callback); ①

// 執行each或queue方法

return this[ optall.queue === false ? "each" : "queue" ](function(){② var opt = jQuery.extend({}, optall), p,

hidden=this.nodeType==1&&jQuery(this).is(":hidden"),//元素節點且隐藏

self = this;// 目前的元素

for ( p in prop ) { ③

//如果是完成的狀态,就直接調用complate函數

if ( prop[p] == "hide" && hidden || prop[p] == "show" && !hidden ) return opt.complete.call(this);

if (( p == "height" || p == "width")&& this.style ){//style高寬度

opt.display = jQuery.css(this, "display");// 儲存目前元素的display

opt.overflow = this.style.overflow;// 保證沒有暗中進行的

}

}

if ( opt.overflow != null )// 超出部分不見

this.style.overflow = "hidden";

opt.curAnim = jQuery.extend({}, prop);//clone傳入的參數prop

jQuery.each( prop, function(name, val){ ④

// 對目前元素的給定的屬性進行變化的操作

var e = new jQuery.fx( self, opt, name ); ⑤

// 傳參的屬性可以用toggle,show,hide,其它

// 調用目前e.show,e.hide,e.val的方法,jQuery.fx.prototype

if ( /toggle|show|hide/.test(val) ) ⑥

e[ val == "toggle" ? hidden ? "show" : "hide" : val ]( prop ); else { ⑦

var parts = al.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/),

start = e.cur(true) || 0;// 目前元素目前屬性的值

// +=" 或 "-=" 來讓元素做相對運動。

if ( parts ) { ⑧

var end = parseFloat(parts[2]), unit = parts[3] || "px"; if ( unit != "px" ) {// 計算開始的值=(end/cur)*start

self.style[ name ] = (end || 1) + unit;

start = ((end || 1) / e.cur(true)) * start;

self.style[ name ] = start + unit;

}

if( parts[1]) end = ((parts[1] == "-="? -1 : 1)* end)+ start;

e.custom( start, end, unit );// 動畫

}

//直接計算start和end的位置來動畫。val是數值的end,start目前的屬性值。

else e.custom( start, val, "" );// 動畫 ⑨

}

});

/ For JS strict compliance

return true;

}); },

Animate通過傳入的參數對于jquery對象中的每個元素的每個訓示的屬性都進行時間上漸變的改變。下面就分析其中的代碼。

jQuery.speed

在①是就通過jquery.speed來進行參數的統一整理。

// 主要用于輔助性的工作

speed: function(speed, easing, fn) {

var opt = speed && speed.constructor == Object ? speed : {

// coplete是至多三個參數的最後一個。看看是否傳入動畫完成回調的函數

complete: fn ||!fn && easing ||jQuery.isFunction( speed ) && speed,

duration: speed,// 持繼的時間,動畫運作的時間。

//找到動畫中屬性随時間漸變的的算法。

easing:fn&&easing || easing && easing.constructor != Function && easing

};

//計算出正确的duration,它支援fast,slow這樣已經定義的常量

opt.duration = (opt.duration &&

(opt.duration.constructor == Number?

opt.duration :

jQuery.fx.speeds[opt.duration]))||jQuery.fx.speeds._default;

// Queueing

opt.old = opt.complete;

//這裡是把complete形成了包裹,看看參數中是否指定隊列操作,

//如果先出列,再執行complete

opt.complete = function(){

//可能通過參數指定queue,this指向是目前的dom元素。

if ( opt.queue !== false ) jQuery(this).dequeue();//出queue

if (jQuery.isFunction( opt.old )) opt.old.call( this );

};

return opt;

},

jquery.speed是對參數進行管理的操作函數。它首先看看speed是不是緊縮型的參數如{ complete:xx, easing:xx, duration:xx}。如果不是,就根據傳入的參數進行判斷,組成緊縮型的對象參數。

由于jquery對象支援fast,slow這樣的常量來代替具體的speed的數值,第二步就是進行speed的處理。如果沒有提供就提供預設的speed。其代碼在jQuery.fx.speeds中speeds:{ slow: 600, fast: 200, _default: 400},定義了三種形式的速度。

接下來是對在完成的時間執行的complete的回調函數進行包裹。包裹就是看看參數中提供了隊列的操作沒有。提供了就進行出隊列的操作。之後再執行complete的回調函數。

jQuery.fn.dequeue = function(type){

type = type || "fx";

return this.each(function(){

var q = queue(this, type);// 得取type的的值

q.shift();// 移出一個

if ( q.length )

q[0].call( this );

});

};

jQuery.fn.dequeue根據type取到目前dom元素的queue。先移出一個。再運作queue中的第一個。

Queue

Java代碼 複制代碼

1. prk/彭仁夔 轉載請注明出處 <A href="http://jljlpch.iteye.com/" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" >http://jljlpch.iteye.com/</A>

2.

3. 在②處和上一部分都看看參數中提供了隊列的操作沒有,有就是進行queue的操作。Queue的操作和each的操作是不一樣的。

4. // 實作隊列操作,為jQuery對象中的每個元素都加type的屬性,值為fn.

5. queue: function(type, fn){

6. // 可能看出支援一個參數的fn 或array形式的集合其type為預設的fx的形式。

7. if(jQuery.isFunction(type)||( type && type.constructor == Array)) {

8. fn = type; type = "fx"; }

9. //沒有參數時或一個參數是字元的type時就從jquery對象第一個元素的data中取

10. //出相對于的type(空就是所有)的隊列中的元素(fn)。

11. if ( !type || (typeof type == "string" && !fn) )

12. return queue( this[0], type );//從queue取出

13. //把fn儲存在jquery對象中的每個元素的data中的對應的type中去。

14. //對于fn是fn的數組集合,就直接設定 data中type為fn的數組

15. //如果是單個的fn,那麼就采用追加的形式追加到data的type的fn數組中。

16. //如果追加的形式,而且之前數組中沒有 fn元素。那麼就執行這個元素。

17. return this.each(function(){

18. if ( fn.constructor == Array )// 數組的形式

19. queue(this, type, fn);// 存儲在元素的type屬性中

20. else {

21. queue(this, type).push( fn );

22. if ( queue(this, type).length == 1 ) fn.call(this);

23. }

24. });

25. },

26. 分析上面的代碼可以看出Queue的操作和each的操作是不太一樣的。Each是對每個元素都執行fn函數。而queue對于每個元素都把fn函數放到自已對應的cache中fx的屬性中儲存,是單個的fn的話,也立馬運作。在②處和each的作用差不多。

27. 在上面的代碼,它還調用了queue(this, type, fn);來實作把把fn存到this元素的data中的對應的type中去。

28. // 為元素加上type的array的屬性,或傳回取到elem上type的值

29. var queue = function( elem, type, array ) {

30. if ( elem ){

31. type = type || "fx";

32. var q = jQuery.data( elem, type + "queue" );

33. if ( !q || array )

34. q = jQuery.data( elem, type + "queue", jQuery.makeArray(array) );

35. }

36. return q;

37. };

38. 這個全局的函數就是在jQuery.data進一步封裝,使它支援預設的fx type和array的類數組的參數。

39. Jquery這裡的Queue實質上沒有起到什麼作用。它本來可以支援一個元素的的連續執行幾個Queue的函數達到更豐富的動畫的效果。估計這裡是沒有完成。

40. ①②③④⑤⑥⑦⑧⑨⑩

41. jQuery.fx

42. ⑤處animate為dom元素的每個指定的屬性都生成了一個fx對象。

43. // 根據參數構成一個對象

44. fx: function( elem, options, prop ){

45. this.options = options;

46. this.elem = elem;

47. this.prop = prop;

48.

49. if ( !options.orig )

50. options.orig = {};

51. }

52. Fx函數是一個建構函數,僅僅是把參數變成本對象的屬性。以便于fx對象的其它方法來使用這些參數。在⑥處就是通過調用fx 的方法show或hidden來完成一個屬性的逐漸的改變。在⑨是通過custom方法來直接進行一個動畫。

53. 先看一下show或hidden:

54. show: function(){

55. // 儲存目前的,以被修改之後能得到初始的值

56. this.options.orig[this.prop]=jQuery.attr(this.elem.style,this.prop);

57. this.options.show = true;//标明是進行show操作

58. this.custom(0, this.cur());

59. //讓最開始時以1px的寬或高度來顯示。防止内容flash

60. if ( this.prop == "width" || this.prop == "height" )

61. this.elem.style[this.prop] = "1px";

62. jQuery(this.elem).show();

63. },

64. hide: function(){

65. // 儲存目前的,以被修改之後能得到初始的值

66. this.options.orig[this.prop]=jQuery.attr(this.elem.style,this.prop);

67. this.options.hide = true;//辨別是進行hide操作

68. this.custom(this.cur(), 0); },

69. show和hide是在指定元素的屬性為show或hide的時候調用的,如height: "show", width: "show", opacity: "show"。它們都是先儲存原始的改悔。之後調用custom來完成動畫。和⑨處是一樣的。

70. 也就是說完成動畫的工作在custom中:

71. // 開動一個動畫

72. custom: function(from, to, unit){

73. this.startTime = now();//動畫開始的時候

74. this.start = from;//位置開始點

75. this.end = to;//位置結果點

76. this.unit = unit || this.unit || "px";

77. this.now = this.start;//位置目前點

78. //state 是時間間隔在總的duration的比率

79. //pos 是按一定算法把時間上的比率折算到位置上的比率

80. this.pos = this.state = 0;

81. // 根據this.now位置目前點的值來設定元素的屬性顯示出來

82. this.update();

83.

84. var self = this;

85. function t(gotoEnd){

86. return self.step(gotoEnd);// 調用step(gotoEnd)//本對象的

87. }

88. t.elem = this.elem;//删除的時候做判斷用

89. //timers 棧是公共的,不同的元素的不同的屬性step都是放在這裡面。

90. jQuery.timers.push(t);

91.

92. if ( jQuery.timerId == null ) {

93. jQuery.timerId = setInterval(function(){

94. var timers = jQuery.timers;

95. //倒是覺得這裡會有同步沖突的問題。Ext.observable中就有解決方法

96. for ( var i = 0; i < timers.length; i++ )

97. //當一個屬性的動畫完成,或強迫完成的時候,把step從數組中删除.

98. //同時把i的位置不改變。繼續下一個。

99. if ( !timers[i]() ) timers.splice(i--, 1);

100. //說明還有屬性的動畫沒有完成,step還在timers中。

101. //那麼就不clearInterval,13ms之後再繼續。直到數組

102. //中所有的step都被删除。

103. if ( !timers.length ) {

104. clearInterval( jQuery.timerId );

105. jQuery.timerId = null;

106. }

107. }, 13);

108. }

109. },

110. 在custom中為fx對象動态地追加了幾個屬性。Start和end屬性指的屬性值變化的開始和結束位置。這是屬性值發生變化的範圍。Now是在Start和end 範圍的某一個點,也就是目前要比屬性設定值。這個值是根據時間的間隔比率再通過一定的算法來得出的。 pos 和state一個是位置上的比率,一個是時間上比率,值在0~1之間。

111. Custom通過this.now = this.start;和this.update(); 來設起始位置的樣式屬性。

112. // 為元素設值,更新顯示

113. update: function(){

114. //可以在顯示之前進行自定義的顯示操作

115. // 這裡可以是改變this.now或元素的其它屬性。

116. // 改變this.now是改變動畫的軌迹,改變其它的屬性會有更多的效果

117. if ( this.options.step )

118. this.options.step.call( this.elem, this.now, this );

119. //根據this.now來改變/設值目前屬性的值。也就改變了樣式。

120. (jQuery.fx.step[this.prop] || jQuery.fx.step._default)( this );

121.

122. // 對于高度和寬度,肯定是要能看出效果的,故采用display=block。

123. if ( ( this.prop == "height" || this.prop == "width" )

124. && this.elem.style )

125. this.elem.style.display = "block";

126. },

prk/彭仁夔 轉載請注明出處 http://jljlpch.iteye.com/

在②處和上一部分都看看參數中提供了隊列的操作沒有,有就是進行queue的操作。Queue的操作和each的操作是不一樣的。

// 實作隊列操作,為jQuery對象中的每個元素都加type的屬性,值為fn.

queue: function(type, fn){

// 可能看出支援一個參數的fn或array形式的集合其type為預設的fx的形式。

if(jQuery.isFunction(type)||( type && type.constructor == Array)) {

fn = type; type = "fx"; }

//沒有參數時或一個參數是字元的type時就從jquery對象第一個元素的data中取

//出相對于的type(空就是所有)的隊列中的元素(fn)。

if ( !type || (typeof type == "string" && !fn) )

return queue( this[0], type );//從queue取出

//把fn儲存在jquery對象中的每個元素的data中的對應的type中去。

//對于fn是fn的數組集合,就直接設定data中type為fn的數組

//如果是單個的fn,那麼就采用追加的形式追加到data的type的fn數組中。

//如果追加的形式,而且之前數組中沒有fn元素。那麼就執行這個元素。

return this.each(function(){

if ( fn.constructor == Array )// 數組的形式

queue(this, type, fn);// 存儲在元素的type屬性中

else {

queue(this, type).push( fn );

if ( queue(this, type).length == 1 ) fn.call(this);

}

});

},

分析上面的代碼可以看出Queue的操作和each的操作是不太一樣的。Each是對每個元素都執行fn函數。而queue對于每個元素都把fn函數放到自已對應的cache中fx的屬性中儲存,是單個的fn的話,也立馬運作。在②處和each的作用差不多。

在上面的代碼,它還調用了queue(this, type, fn);來實作把把fn存到this元素的data中的對應的type中去。

// 為元素加上type的array的屬性,或傳回取到elem上type的值

var queue = function( elem, type, array ) {

if ( elem ){

type = type || "fx";

var q = jQuery.data( elem, type + "queue" );

if ( !q || array )

q = jQuery.data( elem, type + "queue", jQuery.makeArray(array) );

}

return q;

};

這個全局的函數就是在jQuery.data進一步封裝,使它支援預設的fx type和array的類數組的參數。

Jquery這裡的Queue實質上沒有起到什麼作用。它本來可以支援一個元素的的連續執行幾個Queue的函數達到更豐富的動畫的效果。估計這裡是沒有完成。

①②③④⑤⑥⑦⑧⑨⑩

jQuery.fx

⑤處animate為dom元素的每個指定的屬性都生成了一個fx對象。

// 根據參數構成一個對象

fx: function( elem, options, prop ){

this.options = options;

this.elem = elem;

this.prop = prop;

if ( !options.orig )

options.orig = {};

}

Fx函數是一個建構函數,僅僅是把參數變成本對象的屬性。以便于fx對象的其它方法來使用這些參數。在⑥處就是通過調用fx的方法show或hidden來完成一個屬性的逐漸的改變。在⑨是通過custom方法來直接進行一個動畫。

先看一下show或hidden:

show: function(){

// 儲存目前的,以被修改之後能得到初始的值

this.options.orig[this.prop]=jQuery.attr(this.elem.style,this.prop);

this.options.show = true;//标明是進行show操作

this.custom(0, this.cur());

//讓最開始時以1px的寬或高度來顯示。防止内容flash

if ( this.prop == "width" || this.prop == "height" )

this.elem.style[this.prop] = "1px";

jQuery(this.elem).show();

},

hide: function(){

// 儲存目前的,以被修改之後能得到初始的值

this.options.orig[this.prop]=jQuery.attr(this.elem.style,this.prop);

this.options.hide = true;//辨別是進行hide操作

this.custom(this.cur(), 0); },

show和hide是在指定元素的屬性為show或hide的時候調用的,如height: "show", width: "show", opacity: "show"。它們都是先儲存原始的改悔。之後調用custom來完成動畫。和⑨處是一樣的。

也就是說完成動畫的工作在custom中:

// 開動一個動畫

custom: function(from, to, unit){

this.startTime = now();//動畫開始的時候

this.start = from;//位置開始點

this.end = to;//位置結果點

this.unit = unit || this.unit || "px";

this.now = this.start;//位置目前點

//state是時間間隔在總的duration的比率

//pos是按一定算法把時間上的比率折算到位置上的比率

this.pos = this.state = 0;

//根據this.now位置目前點的值來設定元素的屬性顯示出來

this.update();

var self = this;

function t(gotoEnd){

return self.step(gotoEnd);// 調用step(gotoEnd)//本對象的

}

t.elem = this.elem;//删除的時候做判斷用

//timers棧是公共的,不同的元素的不同的屬性step都是放在這裡面。

jQuery.timers.push(t);

if ( jQuery.timerId == null ) {

jQuery.timerId = setInterval(function(){

var timers = jQuery.timers;

//倒是覺得這裡會有同步沖突的問題。Ext.observable中就有解決方法

for ( var i = 0; i < timers.length; i++ )

//當一個屬性的動畫完成,或強迫完成的時候,把step從數組中删除.

//同時把i的位置不改變。繼續下一個。

if ( !timers[i]() ) timers.splice(i--, 1);

//說明還有屬性的動畫沒有完成,step還在timers中。

//那麼就不clearInterval,13ms之後再繼續。直到數組

//中所有的step都被删除。

if ( !timers.length ) {

clearInterval( jQuery.timerId );

jQuery.timerId = null;

}

}, 13);

}

},

在custom中為fx對象動态地追加了幾個屬性。Start和end屬性指的屬性值變化的開始和結束位置。這是屬性值發生變化的範圍。Now是在Start和end 範圍的某一個點,也就是目前要比屬性設定值。這個值是根據時間的間隔比率再通過一定的算法來得出的。pos 和state一個是位置上的比率,一個是時間上比率,值在0~1之間。

Custom通過this.now = this.start;和this.update();來設起始位置的樣式屬性。

// 為元素設值,更新顯示

update: function(){

//可以在顯示之前進行自定義的顯示操作

//這裡可以是改變this.now或元素的其它屬性。

//改變this.now是改變動畫的軌迹,改變其它的屬性會有更多的效果

if ( this.options.step )

this.options.step.call( this.elem, this.now, this );

//根據this.now來改變/設值目前屬性的值。也就改變了樣式。

(jQuery.fx.step[this.prop] || jQuery.fx.step._default)( this );

// 對于高度和寬度,肯定是要能看出效果的,故采用display=block。

if ( ( this.prop == "height" || this.prop == "width" )

&& this.elem.style )

this.elem.style.display = "block";

},

Java代碼 複制代碼

1. prk/彭仁夔 轉載請注明出處 <A href="http://jljlpch.iteye.com/" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" >http://jljlpch.iteye.com/</A>

2.

3. 通過udate設定起始位置的樣式屬性之後,custom第二步就是采用setInterval

4. 每隔13ms就執行一次目前的fx對象的step方法。該方法實作了動畫結束的掃尾工作和動畫過程中按一定的算法來計算this.now 的值。因為這個值的改變,之後調用update就可以改變樣式的屬性。

5. 這樣一來,就實作了元素的某個屬性的漸變過程。

6. // 動畫的每一個步驟

7. step: function(gotoEnd){

8. var t = now();//運作到目前的時間,因為是13ms才運作一次。

9. // 強行指定結束或目前時間大于startTime+duration

10. if ( gotoEnd || t > this.options.duration + this.startTime ) {

11. this.now = this.end;//目前的位置為結束位置

12. this.pos = this.state = 1;//目前的state,pos的比率為1.最大。

13. this.update();//顯示

14. //辨別這個屬性的動畫已經完成

15. this.options.curAnim[ this.prop ] = true;

16. //再一次判斷是否完成

17. var done = true;

18. for ( var i in this.options.curAnim )

19. if ( this.options.curAnim[i] !== true )

20. done = false;

21.

22. if ( done ) {

23. if ( this.options.display != null ) {// 恢複overflow

24. this.elem.style.overflow = this.options.overflow;

25. // 恢複 display

26. this.elem.style.display = this.options.display;

27. //判斷其是否恢複成功,

28. if ( jQuery.css(this.elem, "display") == "none" )

29. this.elem.style.display = "block";

30. }

31.

32. //如果是hide的操作

33. if ( this.options.hide )

34. this.elem.style.display = "none";

35.

36. // 如果元素已經show或hide,恢複其動畫改變的屬性

37. if ( this.options.hide || this.options.show )

38. for ( var p in this.options.curAnim )

39. jQuery.attr(this.elem.style, p,

40. this.options.orig[p]);

41. }

42.

43. if ( done )// 運作complete的回調函數

44. this.options.complete.call( this.elem );

45.

46. return false;

47. } else {

48. var n = t - this.startTime;//時間間隔

49. this.state = n / this.options.duration;//時間間隔比率

50.

51. //根據時間間隔的比率再按一定的算法比率來計算

52. //目前的運動的位置點的比率。預設是 swing的算法

53. this.pos = jQuery.easing[this.options.easing ||

54. (jQuery.easing.swing ? "swing" : "linear")]

55. (this.state, n, 0, 1, this.options.duration);

56. //目前的位置

57. this.now = this.start + ((this.end - this.start) * this.pos);

58.

59. // 顯示

60. this.update();

61. }

62.

63. return true;

64. }

65. Step中第一部分是完成時的掃尾工作,恢複動畫時改變的屬性和運作complete的回調函數。第二部分就是計算this.now 的值之後顯示出來。目前jquery提供了兩種算法來計算從時間間隔比率轉換成位置上的比率。

66. easing: {

67. linear: function( p, n, firstNum, diff ) {

68. return firstNum + diff * p;

69. },

70. swing: function( p, n, firstNum, diff ) {

71. return ((-Math.cos(p*Math.PI)/2) + 0.5) * diff + firstNum;

72. }

73. },

74. 這就是它的算法。對于linear的形式,Jquery采用了1:1的關系來計算的。

75. Stop

76. 一個動畫,有的時間可能會出現在沒有運作完成就中斷。Stop就是對這個進行操作的。

77. stop: function(clearQueue, gotoEnd){

78. var timers = jQuery.timers;

79. if (clearQueue) this.queue([]);// 清除

80. this.each(function(){

81. // 倒序是為了能把在loop過程加入timers的目前元素的屬性的動畫step也給删除。

82. for ( var i = timers.length - 1; i >= 0; i-- )

83. if ( timers[i].elem == this ) {

84. if (gotoEnd) timers[i](true); // 強迫動畫結束

85. timers.splice(i, 1);

86. }

87. });

88. // start the next in the queue if the last step wasn't forced

89. if (!gotoEnd) this.dequeue();

90.

91. return this;

92. }

93. 在stop中,我們可以看出step(force)中的參數的作用。這個強迫動畫到最後一步,即動畫結束進行掃尾工作。這裡的 jQuery.timers是公共的集合。在custom中的setInterval就是對它進行操作的。

繼續閱讀