jQuery 1.9.1源码分析系列(十五)之动画处理(2)

  第四,调用propFilter修正css特征名称以便能被浏览器识别,其中需要注意的是borderWidth/padding/margin指的不是一个css特征,而是四个(上下左右)

//经过propFilter,animation.opts.specialEasing添加了相应的特征 propFilter( props, animation.opts.specialEasing );

  举例说明propFilter修正成果。

  例1,css特征{ height: 200 }的修正后结果为:

props = { height: 200 } animation.opts.specialEasing = {height: undefined}

  例2:,css特征{margin:200}的修正结果为:

props = { marginBottom: 200,marginLeft: 200,marginRight: 200,marginTop: 200 } animation.opts.specialEasing = { marginBottom: undefined,marginLeft: undefined,marginRight: undefined,marginTop: undefined }

  第五,调用defaultPrefilter做适配处理:比如对height/width的动画要求display和overflow为特定的值才能有效果;比如对show/hide动画需要对一大堆css特征值进行动画,并且在函数里就调用createTweens生成缓动动画。

// animationPrefilters[0] = defaultPrefilter for ( ; index < length ; index++ ) { result = animationPrefilters[ index ].call( animation, elem, props, animation.opts ); if ( result ) { return result; } }

  其中animationPrefilters[ index ]值得函数就是defaultPrefilter,defaultPrefilter函数处理有几个比较重要的地方

  defaultPrefilter重点1:内联元素中height/width相关动画需要设置display特征值为inline-block

// height/width overflow pass if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) { //确保没有什么偷偷出来 //记录3个overflow相关特征,因为IE不能改变overflow特征值, //当overflowX和overflowY设置了相同的值 opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; // 内联元素中height/width相关动画需要设置display特征值为inline-block if ( jQuery.css( elem, "display" ) === "inline" && jQuery.css( elem, "float" ) === "none" ) { // 内联元素接受inline-block; // 块级元素必须内嵌在布局上 if ( !jQuery.support.inlineBlockNeedsLayout || css_defaultDisplay( elem.nodeName ) === "inline" ) { style.display = "inline-block"; } else { style.zoom = 1; } } }

  defaultPrefilter重点2:对于height/width动画overflow都要设置为"hidden",动画完成后恢复。这个有利于提高渲染速度。

//对于height/width动画overflow都要设置为"hidden",动画完成后恢复 if ( opts.overflow ) { style.overflow = "hidden"; //收缩包装块 if ( !jQuery.support.shrinkWrapBlocks ) { anim.always(function() { style.overflow = opts.overflow[ 0 ]; style.overflowX = opts.overflow[ 1 ]; style.overflowY = opts.overflow[ 2 ]; }); } }

  defaultPrefilter重点3:show/hide动画的特殊处理:show/hide动画调用genFx得到形如

props = { height: "hide" marginBottom: "hide" marginLeft: "hide" marginRight: "hide" marginTop: "hide" opacity: "hide" paddingBottom: "hide" paddingLeft: "hide" paddingRight: "hide" paddingTop: "hide" width: "hide" }

  需要进行动画处理的特征压入handled列表,并将相应的特征删除,后面会生成相应的缓动动画。

for ( index in props ) { value = props[ index ];   //rfxtypes = /^(?:toggle|show|hide)$/。可以看到最终只有和show/hide的动画才会被饶茹handled中 if ( rfxtypes.exec( value ) ) { delete props[ index ]; toggle = toggle || value === "toggle"; //如果当前节点的状态和指定的状态相同则不需要处理直接进行下一个状态判断 if ( value === ( hidden ? "hide" : "show" ) ) { continue; } handled.push( index ); } } //有需要执行的动画处理则进入分支,里面会对各个特征动画生成缓动动画 length = handled.length; if ( length ) { dataShow = jQuery._data( elem, "fxshow" ) || jQuery._data( elem, "fxshow", {} ); if ( "hidden" in dataShow ) { hidden = dataShow.hidden; } // toggle需要保存状态 - enables .stop().toggle() to "reverse" if ( toggle ) { dataShow.hidden = !hidden; } if ( hidden ) { jQuery( elem ).show(); } else { anim.done(function() { jQuery( elem ).hide(); }); } anim.done(function() { var prop; jQuery._removeData( elem, "fxshow" ); for ( prop in orig ) { jQuery.style( elem, prop, orig[ prop ] ); } }); for ( index = 0 ; index < length ; index++ ) { prop = handled[ index ]; //生成缓动动画 tween = anim.createTween( prop, hidden ? dataShow[ prop ] : 0 ); orig[ prop ] = dataShow[ prop ] || jQuery.style( elem, prop ); if ( !( prop in dataShow ) ) { dataShow[ prop ] = tween.start; if ( hidden ) { tween.end = tween.start; tween.start = prop === "width" || prop === "height" ? 1 : 0; } } } }

  第六,生成缓动动画,show/hide在defaultPrefilter函数里面已经处理(上面的源码)。

createTweens( animation, props );

  我们来看一看createTweens中具体做了什么,先看一下createTweens之前的animation对象


  然后看一下经过createTweens之后的animation对象的tweens数组变成了

  将margin分解成了四个属性(marginTop/Right/Bottom/Left)并且每个属性都有自己的动画特征。

  第七,启动动画计时,定时执行tick

//启动动画计时 jQuery.fx.timer( jQuery.extend( tick, { elem: elem, anim: animation, queue: animation.opts.queue }) );

  最后,将传入的动画结束回调加入延时队列

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wgzzsz.html