在jQuery內部函數Animation中呼叫了createTweens()來建立緩動動畫群組,建立完成後的結果為:
可以看到上面的緩動動畫組有四個原子動畫組成。每一個原子動畫的訊息都包含在裡面了。
仔細查看createTweens函數,其實就是遍歷呼叫了tweeners ["*"]的陣列中的函數(其實只有一個元素)。
function createTweens( animation, props ) { jQuery.each( props, function( prop, value ) { var collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ), index = 0, length = collection.length; for ( ; index < length; index++ ) { if ( collection[ index ].call( animation, prop, value ) ) { // we're done with this property return; } } }); }
再次查看這個tweeners ["*"][0]函數,主要程式碼如下
function( prop, value ) { var end, unit, //根据css特征值获取缓动动画结构 tween = this.createTween( prop, value ), parts = rfxnum.exec( value ), target = tween.cur(), start = +target || 0, scale = 1, maxIterations = 20; if ( parts ) { end = +parts[2]; unit = parts[3] || ( jQuery.cssNumber[ prop ] ? "" : "px" ); //非像素单位的属性 if ( unit !== "px" && start ) { // 从一个非零起点开始迭代, //对于当前属性,如果它使用相同的单位这一过程将是微不足道 // 后备为end,或一个简单的常量 start = jQuery.css( tween.elem, prop, true ) || end || 1; do { //如果前一次迭代为零,加倍,直到我们得到*东西* //使用字符串倍增因子,所以我们不会偶然看到scale不改变 scale = scale || ".5"; // 调整和运行 start = start / scale; jQuery.style( tween.elem, prop, start + unit ); // 更新scale, 默认0或NaN从tween.cur()获取 // 跳出循环,如果scale不变或完成时, 或者我们已经觉得已经足够了 } while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations ); } tween.unit = unit; tween.start = start; //如果提供了+=/-=记号,表示我们正在做一个相对的动画 tween.end = parts[1] ? start + ( parts[1] + 1 ) * end : end; } return tween; }] };
可以看出除了hide/show兩種動畫外的其他動畫都經過tweeners ["*"][0]這個函數封裝了動畫組。其中有幾個關鍵的陣列start/end/unit。特別是對非像素單位的動畫start值獲取費了一番功夫。
還有一個比較關鍵的地方是都用了this.createTween獲取單一css特徵的基礎的動畫特徵。而animation. createTween中直接呼叫jQuery.Tween來處理。接下來我們詳解之。
a.jQuery.Tween
----------------------------------------------- ---------------------------------
jQuery.Tween的結構和jQuery類似
function Tween( elem, options, prop, end, easing ) { return new Tween.prototype.init( elem, options, prop, end, easing ); } jQuery.Tween = Tween; Tween.prototype = { constructor: Tween, init: function( elem, options, prop, end, easing, unit ) { this.elem = elem; this.prop = prop; this.easing = easing || "swing"; this.options = options; this.start = this.now = this.cur(); this.end = end; this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); }, cur: function() {...}, run: function( percent ) {...} }; Tween.prototype.init.prototype = Tween.prototype;
是不是有一種很熟悉的趕腳。
裡面cur函數用來取得目前的css特徵值
cur: function() { var hooks = Tween.propHooks[ this.prop ]; return hooks && hooks.get ? hooks.get( this ) : Tween.propHooks._default.get( this ); },
而run函數則會在每個動畫時間點上對正在進行的動畫的每個特徵值進行處理。
主要是兩個步驟:
1.計算動畫當前進度pos與動畫目前位置now
//如果有动画时长则使用jQuery.easing计算出缓动动画进度eased,否则进度eased为percent //并根据进度得到当前动画位置now if ( this.options.duration ) { this.pos = eased = jQuery.easing[ this.easing ]( percent, this.options.duration * percent, 0, 1, this.options.duration ); } else { this.pos = eased = percent; } this.now = ( this.end - this.start ) * eased + this.start;
2.依當前進度情況設定css特徵值
//设置css特征值 if ( hooks && hooks.set ) { hooks.set( this ); } else { Tween.propHooks._default.set( this ); } return this;
可見生成緩動動畫這一步驟處理才是整個動畫的核心:
創造緩動動畫組,每一個原子動畫都包含了每一個原子css屬性動畫的各種必要參數以及動畫函數
不同的是hide/show直接在defaultPrefilter中創建了這個緩動動畫組(所有的屬性都默認是px單位),其他的動畫在調用createTweens時創建緩動動畫組。
還記不記得在創建動畫的時候有個tick函數,這個tick函數會在每隔一個步長的時間調用一次
tick = function() { ... length = animation.tweens.length; for ( ; index < length ; index++ ) { animation.tweens[ index ].run( percent ); } ... }
看到沒,每一個原子動畫有自己的run函數來執行自己的動畫,這在創建緩動動畫組的時候就建好了的。
好了,整理一下動畫的整個核心流程:
1.先根據參數呼叫jQuery.speed取得動畫相關參數,得到一個類似如下的物件;並且產生動畫執行函數doAnimation使用.queue壓入佇列並馬上執行
opt = { complete: fnction(){...},//动画执行完成的回调 duration: 400,//动画执行时长 easing: "swing",//动画效果 queue: "fx",//动画队列 old: false/fnction(){...}, }
2.doAnimation中呼叫建立一個延時對象,使用延時對象的promise方法建構一個動畫對象animation(延時對象 動畫特徵列表),最後給animation添加動畫執行完成後的回調函數。
3.呼叫jQuery內部函數proFilter修正css特徵名以便能被當前瀏覽器識別,並將某些複合css特徵分解(例如padding分解成paddingTop / Right/Bottom/ Left).
4.呼叫jQuery內部函數defaultPrefilter做動畫能夠正常運作前提條件修正:例如對height/width動畫display和overflow需要特定的值。特別要注意的是
對於show/hide動畫,在之前就調用genFx將需要執行動畫的css特徵提取了出來,在defaultPrefilter函數裡直接調用動畫對象animation.createTween給每一個CSS動畫屬性添加對應的緩動動畫對象(包含動畫參數及動畫函數如run)壓入緩動動畫組animation.tweens中
5.呼叫jQuery內部函數createTweens將除開show/hide之外的動畫每一個css動畫特徵使用animation.createTween創建緩動動畫物件(包括動畫參數和動畫函數如run),壓入緩動動畫組animation.tweens中
6.啟動動畫計時,在每個時間點上執行tick函數來為對應的css特徵值設定運動值。
其中css特徵值運動的進度百分比是
remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), temp = remaining / animation.duration || 0, percent = 1 - temp
得到的percent是符合時間法則的。代入這個percent設定準確的css特徵值,以刷新動畫顯示。
8.動畫完成後呼叫動畫完成回呼。
關於小編給大家分享的jQuery 1.9.1源碼分析系列(十五)動畫處理之緩動動畫核心Tween 全部內容就到此結束了,有問題歡迎給我留言我會在第一時間和大家取得聯繫的。