当前位置 主页 > 服务器问题 > win服务器问题汇总 >

    Jquery1.9.1源码分析系列(十五)动画处理之外篇

    栏目:win服务器问题汇总 时间:2019-11-29 10:14

    a.动画兼容Tween.propHooks

      Tween.propHooks提供特殊情况下设置、获取css特征值的方法,结构如下

    Tween.propHooks = {
      _default: {
        get: function(){...},
        set: function(){...}
      },
      scrollTop: {
        set: function(){...}
      }
      scrollLeft: {
        set: function(){...}
      }
    } 

      Tween.propHooks.scrollTop 和Tween.propHooks.scrollLeft两个主要是在ie8离线状态下会出现混乱而把css特征值保存到节点上

    set: function( tween ) {
      if ( tween.elem.nodeType && tween.elem.parentNode ) {
        tween.elem[ tween.prop ] = tween.now;
      }
    } 

      Tween.propHooks._default的get方法会尝试直接从节点上取得css的tween.prop特征值,如果取不到则使用jQuery.css()方式来获取。该方法处理中,简单的值如“10px”会被解析为浮点数;复杂的值,如“旋转(1rad)”返回原样。并对返回结果再做处理:空字符串, null, undefined 和 "auto"都转化为0;其他情况不变。

    get: function( tween ) {
      var result;
      if ( tween.elem[ tween.prop ] != null &&
        (!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) {
        return tween.elem[ tween.prop ];
      }
      //传递一个空字符串作为第三个参数的.css会自动尝试parseFloat,
      //并返回到一个字符串,如果解析失败的话。
      //所以,简单的值,如“10px”会被被解析为浮点数。复杂的值,如“旋转(1rad)”返回原样。
      result = jQuery.css( tween.elem, tween.prop, "" );
      // 空字符串, null, undefined 和 "auto"都转化为0
      return !result || result === "auto" ? 0 : result;
    } 

      Tween.propHooks._default的set方法先会尝试jQuery.fx.step[ tween.prop ]来设置向下兼容;否则会使用jQuery.style来设置css特征值;最极端情况则会将特征值直接保存在节点上

    set: function( tween ) {
      //使用step hook向下兼容 - 使用cssHook如果他存在 - 使用.style如果可用的话
      //使用直接的特征值如果可用可用的话
      if ( jQuery.fx.step[ tween.prop ] ) {
        jQuery.fx.step[ tween.prop ]( tween );
      } else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) {
        jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );
      } else {
        tween.elem[ tween.prop ] = tween.now;
      }
    } 

    b. 动画专用对象jQuery.fx

      jQuery.fx封装了一些用来执行动画动作的函数,结构如下

    jQuery.fx = {
      tick = function () {...},//每个时间点都会执行的函数外壳,会取出jQuery.timers中的函数执行
      timer = function ( timer ) {...},//执行参数中的函数并启动计时
      interval = 13, //计时步长
      start = function () {...},//启动计时
      stop = function () {...},//停止计时
      speeds = {slow: 600,fast: 200,_default: 400},//动画速度(完整动画执行时间)
      step = {}//向下兼容<1.8扩展点
    } 

      详细的源码分析如下

    jQuery.fx = Tween.prototype.init;
    //每个时间点都会执行的函数外壳,会取出jQuery.timers中的函数执行
    jQuery.fx.tick = function() {
      var timer,
      timers = jQuery.timers,
      i = 0;
      fxNow = jQuery.now();
      for ( ; i < timers.length; i++ ) {
        timer = timers[ i ];
        // Checks the timer has not already been removed
        if ( !timer() && timers[ i ] === timer ) {
          timers.splice( i--, 1 );
        }
      }
      if ( !timers.length ) {
        jQuery.fx.stop();
      }
      fxNow = undefined;
    };
    //执行参数中的函数并启动计时
    jQuery.fx.timer = function( timer ) {
      if ( timer() && jQuery.timers.push( timer ) ) {
        jQuery.fx.start();
      }
    };
    //计时步长
    jQuery.fx.interval = 13;
    //启动计时
    jQuery.fx.start = function() {
      if ( !timerId ) {
        timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval );
      }
    };
    //停止计时
    jQuery.fx.stop = function() {
      clearInterval( timerId );
      timerId = null;
    };
    //动画速度(完整动画执行时间)
    jQuery.fx.speeds = {
      slow: 600,
      fast: 200,
      // Default speed
      _default: 400
    };
    //向下兼容<1.8扩展点
    jQuery.fx.step = {}; 
      这里其中执行动画的关键源码是
    //动画入口函数function Animation( elem, properties, options ){
      ...
      jQuery.fx.timer(
        jQuery.extend( tick, {
          elem: elem,
          anim: animation,
          queue: animation.opts.queue
        })
      );
      ...
    }
    //执行参数中的函数并启动计时
    jQuery.fx.timer = function( timer ) {
      if ( timer() && jQuery.timers.push( timer ) ) {
        jQuery.fx.start();
      }
    };
    //计时步长
    jQuery.fx.interval = 13;
    //启动计时
    jQuery.fx.start = function() {
      if ( !timerId ) {
        timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval );
      }
    };