jQuery 1.9.1源碼分析系列(十五)動(dòng)畫(huà)處理之緩動(dòng)動(dòng)畫(huà)核心Tween
在jQuery內(nèi)部函數(shù)Animation中調(diào)用到了createTweens()來(lái)創(chuàng)建緩動(dòng)動(dòng)畫(huà)組,創(chuàng)建完成后的結(jié)果為:

可以看到上面的緩動(dòng)動(dòng)畫(huà)組有四個(gè)原子動(dòng)畫(huà)組成。每一個(gè)原子動(dòng)畫(huà)的信息都包含在里面了。
仔細(xì)查看createTweens函數(shù),實(shí)際上就是遍歷調(diào)用了tweeners ["*"]的數(shù)組中的函數(shù)(實(shí)際上就只有一個(gè)元素)。
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;
}
}
});
}
再次查看這個(gè)tweeners ["*"][0]函數(shù),主要代碼如下
function( prop, value ) {
var end, unit,
//根據(jù)css特征值獲取緩動(dòng)動(dòng)畫(huà)結(jié)構(gòu)
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 ) {
// 從一個(gè)非零起點(diǎn)開(kāi)始迭代,
//對(duì)于當(dāng)前屬性,如果它使用相同的單位這一過(guò)程將是微不足道
// 后備為end,或一個(gè)簡(jiǎn)單的常量
start = jQuery.css( tween.elem, prop, true ) || end || 1;
do {
//如果前一次迭代為零,加倍,直到我們得到*東西*
//使用字符串倍增因子,所以我們不會(huì)偶然看到scale不改變
scale = scale || ".5";
// 調(diào)整和運(yùn)行
start = start / scale;
jQuery.style( tween.elem, prop, start + unit );
// 更新scale, 默認(rèn)0或NaN從tween.cur()獲取
// 跳出循環(huán),如果scale不變或完成時(shí), 或者我們已經(jīng)覺(jué)得已經(jīng)足夠了
} while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations );
}
tween.unit = unit;
tween.start = start;
//如果提供了+=/-=記號(hào),表示我們正在做一個(gè)相對(duì)的動(dòng)畫(huà)
tween.end = parts[1] ? start + ( parts[1] + 1 ) * end : end;
}
return tween;
}]
};
可以看出除了hide/show兩種動(dòng)畫(huà)外的其他動(dòng)畫(huà)都經(jīng)過(guò)tweeners ["*"][0]這個(gè)函數(shù)封裝了動(dòng)畫(huà)組。其中有幾個(gè)關(guān)鍵的數(shù)組start/end/unit。特別是對(duì)非像素單位的動(dòng)畫(huà)start值獲取費(fèi)了一番功夫。
還有一個(gè)比較關(guān)鍵的地方是都用了this.createTween獲取單個(gè)css特征的基礎(chǔ)的動(dòng)畫(huà)特征。而animation. createTween中直接調(diào)用jQuery.Tween來(lái)處理。接下來(lái)我們?cè)斀庵?/p>
a.jQuery.Tween
--------------------------------------------------------------------------------
jQuery.Tween的結(jié)構(gòu)和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函數(shù)用來(lái)獲取當(dāng)前的css特征值
cur: function() {
var hooks = Tween.propHooks[ this.prop ];
return hooks && hooks.get ?
hooks.get( this ) :
Tween.propHooks._default.get( this );
},
而run函數(shù)則會(huì)在每個(gè)動(dòng)畫(huà)時(shí)間點(diǎn)上對(duì)正在進(jìn)行的動(dòng)畫(huà)的每個(gè)特征值進(jìn)行處理。
主要是兩個(gè)步驟:
1.計(jì)算動(dòng)畫(huà)當(dāng)前進(jìn)度pos和動(dòng)畫(huà)當(dāng)前位置now
//如果有動(dòng)畫(huà)時(shí)長(zhǎng)則使用jQuery.easing計(jì)算出緩動(dòng)動(dòng)畫(huà)進(jìn)度eased,否則進(jìn)度eased為percent
//并根據(jù)進(jìn)度得到當(dāng)前動(dòng)畫(huà)位置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.根據(jù)當(dāng)前進(jìn)度情況設(shè)置css特征值
//設(shè)置css特征值
if ( hooks && hooks.set ) {
hooks.set( this );
} else {
Tween.propHooks._default.set( this );
}
return this;
可見(jiàn)生成緩動(dòng)動(dòng)畫(huà)這一步處理才是整個(gè)動(dòng)畫(huà)的核心:
創(chuàng)建緩動(dòng)動(dòng)畫(huà)組,每一個(gè)原子動(dòng)畫(huà)都包含了每一個(gè)原子css屬性動(dòng)畫(huà)的各種必要參數(shù)以及動(dòng)畫(huà)函數(shù)

不同的是hide/show直接在defaultPrefilter中創(chuàng)建了這個(gè)緩動(dòng)動(dòng)畫(huà)組(所有的屬性都默認(rèn)是px單位),其他的動(dòng)畫(huà)在調(diào)用createTweens時(shí)創(chuàng)建緩動(dòng)動(dòng)畫(huà)組。
還記不記得在創(chuàng)建動(dòng)畫(huà)的時(shí)候有個(gè)tick函數(shù),這個(gè)tick函數(shù)會(huì)在每隔一個(gè)步長(zhǎng)的時(shí)間調(diào)用一次
tick = function() {
...
length = animation.tweens.length;
for ( ; index < length ; index++ ) {
animation.tweens[ index ].run( percent );
}
...
}
看到?jīng)],每一個(gè)原子動(dòng)畫(huà)有自己的run函數(shù)來(lái)執(zhí)行自己的動(dòng)畫(huà),這在創(chuàng)建緩動(dòng)動(dòng)畫(huà)組的時(shí)候就建好了的。
好了,整理一下動(dòng)畫(huà)的整個(gè)核心流程:
1.先根據(jù)參數(shù)調(diào)用jQuery.speed獲取動(dòng)畫(huà)相關(guān)參數(shù),得到一個(gè)類似如下的對(duì)象;并且生成動(dòng)畫(huà)執(zhí)行函數(shù)doAnimation使用.queue壓入隊(duì)列并馬上執(zhí)行
opt = {
complete: fnction(){...},//動(dòng)畫(huà)執(zhí)行完成的回調(diào)
duration: 400,//動(dòng)畫(huà)執(zhí)行時(shí)長(zhǎng)
easing: "swing",//動(dòng)畫(huà)效果
queue: "fx",//動(dòng)畫(huà)隊(duì)列
old: false/fnction(){...},
}
2.doAnimation中調(diào)用創(chuàng)建一個(gè)延時(shí)對(duì)象,使用延時(shí)對(duì)象的promise方法構(gòu)造一個(gè)動(dòng)畫(huà)對(duì)象animation(延時(shí)對(duì)象+動(dòng)畫(huà)特征列表),最后給animation添加動(dòng)畫(huà)執(zhí)行完成后的回調(diào)函數(shù)。
3.調(diào)用jQuery內(nèi)部函數(shù)proFilter修正css特征名以便能被當(dāng)前瀏覽器識(shí)別,并將某些復(fù)合css特征分解(比如padding分解成paddingTop / Right/ Bottom/ Left).
4.調(diào)用jQuery內(nèi)部函數(shù)defaultPrefilter做動(dòng)畫(huà)能夠正常運(yùn)行前提條件修正:比如對(duì)height/width動(dòng)畫(huà)display和overflow需要特定的值。特別需要注意的是
對(duì)于show/hide動(dòng)畫(huà),在之前就調(diào)用genFx將需要執(zhí)行動(dòng)畫(huà)的css特征提取了出來(lái),在defaultPrefilter函數(shù)里直接調(diào)用動(dòng)畫(huà)對(duì)象animation.createTween給每一個(gè)CSS動(dòng)畫(huà)屬性添加對(duì)應(yīng)的緩動(dòng)動(dòng)畫(huà)對(duì)象(包括動(dòng)畫(huà)參數(shù)和動(dòng)畫(huà)函數(shù)如run)壓入緩動(dòng)動(dòng)畫(huà)組animation.tweens中
5.調(diào)用jQuery內(nèi)部函數(shù)createTweens將除開(kāi)show/hide之外的動(dòng)畫(huà)每一個(gè)css動(dòng)畫(huà)特征使用animation.createTween創(chuàng)建緩動(dòng)動(dòng)畫(huà)對(duì)象(包括動(dòng)畫(huà)參數(shù)和動(dòng)畫(huà)函數(shù)如run),壓入緩動(dòng)動(dòng)畫(huà)組animation.tweens中
6.啟動(dòng)動(dòng)畫(huà)計(jì)時(shí),在每個(gè)時(shí)間點(diǎn)上執(zhí)行tick函數(shù)來(lái)給相應(yīng)的css特征值設(shè)置運(yùn)動(dòng)值。
其中css特征值運(yùn)動(dòng)的進(jìn)度百分比是
remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), temp = remaining / animation.duration || 0, percent = 1 - temp
得到的percent是符合時(shí)間規(guī)律的。代入這個(gè)percent設(shè)置準(zhǔn)確的css特征值,以刷新動(dòng)畫(huà)顯示。
8.動(dòng)畫(huà)完成后調(diào)用動(dòng)畫(huà)完成回調(diào)。
關(guān)于小編給大家分享的jQuery 1.9.1源碼分析系列(十五)動(dòng)畫(huà)處理之緩動(dòng)動(dòng)畫(huà)核心Tween 全部?jī)?nèi)容就到此結(jié)束了,有問(wèn)題歡迎給我留言我會(huì)在第一時(shí)間和大家取得聯(lián)系的。
- jQuery1.9.1針對(duì)checkbox的調(diào)整方法(prop)
- jQuery 1.9.1源碼分析系列(十)事件系統(tǒng)之綁定事件
- jQuery-1.9.1源碼分析系列(十)事件系統(tǒng)之事件體系結(jié)構(gòu)
- jQuery-1.9.1源碼分析系列(十)事件系統(tǒng)之事件包裝
- Jquery1.9.1源碼分析系列(六)延時(shí)對(duì)象應(yīng)用之jQuery.ready
- jQuery 1.9.1源碼分析系列(十三)之位置大小操作
- jQuery 1.9.1源碼分析系列(十四)之常用jQuery工具
- jQuery 1.9.1源碼分析系列(十五)之動(dòng)畫(huà)處理
- Jquery1.9.1源碼分析系列(十五)動(dòng)畫(huà)處理之外篇
相關(guān)文章
快速解決jquery.touchSwipe左右滑動(dòng)和垂直滾動(dòng)條沖突
這篇文章主要介紹了快速解決jquery.touchSwipe左右滑動(dòng)和垂直滾動(dòng)條沖突問(wèn)題,感興趣的小伙伴們可以參考一下2016-04-04
jQuery實(shí)現(xiàn)菜單欄導(dǎo)航效果
這篇文章主要為大家詳細(xì)介紹了jQuery實(shí)現(xiàn)簡(jiǎn)單菜單欄導(dǎo)航效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-08-08
ajax 文件上傳應(yīng)用簡(jiǎn)單實(shí)現(xiàn)
今天看到一個(gè)jquery插件jquery.fileupload.v.1.5.0,自己試著結(jié)合java做了一個(gè)ajax的文件上傳小應(yīng)用2009-03-03
jQuery簡(jiǎn)單倒計(jì)時(shí)效果完整示例
這篇文章主要介紹了jQuery簡(jiǎn)單倒計(jì)時(shí)效果,結(jié)合完整實(shí)例形式分析了jQuery針對(duì)日期與時(shí)間的計(jì)算與頁(yè)面元素動(dòng)態(tài)操作相關(guān)技巧,需要的朋友可以參考下2016-09-09
jQuery源碼分析-04 選擇器-Sizzle-工作原理分析
在分析Sizzle源碼之前,先整理一下選擇器的工作原理,先明確一些選擇器中用到的名詞,后邊閱讀時(shí)不會(huì)有歧義2011-11-11
jQuery事件綁定用法詳解(附bind和live的區(qū)別)
這篇文章主要介紹了jQuery事件綁定用法,結(jié)合實(shí)例形式較為詳細(xì)的分析了jQuery事件綁定的實(shí)現(xiàn)原理與相關(guān)注意事項(xiàng),并附帶了相關(guān)綁定方法的使用說(shuō)明,重點(diǎn)介紹了bind和live的區(qū)別,需要的朋友可以參考下2016-01-01
jQuery實(shí)現(xiàn)產(chǎn)品對(duì)比功能附源碼下載
一些電商網(wǎng)站產(chǎn)品或評(píng)測(cè)網(wǎng)站會(huì)為用戶提供產(chǎn)品對(duì)比的功能,用戶只需勾選多個(gè)需要對(duì)比的產(chǎn)品,就可以進(jìn)行比對(duì),下文給大家?guī)?lái)了jQuery實(shí)現(xiàn)產(chǎn)品對(duì)比功能,一起看下吧2016-08-08
基于jQuery的公告無(wú)限循環(huán)滾動(dòng)實(shí)現(xiàn)代碼
今天看到一個(gè)網(wǎng)站的公告欄一個(gè)小效果,如果有2條公告或以上就有個(gè)滾動(dòng)效果,特整理下分享給大家2012-05-05
jQuery使用正則表達(dá)式替換dom元素標(biāo)簽用法示例
這篇文章主要介紹了jQuery使用正則表達(dá)式替換dom元素標(biāo)簽的方法,結(jié)合具體實(shí)例形式分析了jQuery正則替換的操作技巧,需要的朋友可以參考下2017-01-01

