jQuery 1.9.1源码分析系列(十五)动画处理之缓动动画核心Tween


Posted in Javascript onDecember 03, 2015

在jQuery内部函数Animation中调用到了createTweens()来创建缓动动画组,创建完成后的结果为:

jQuery 1.9.1源码分析系列(十五)动画处理之缓动动画核心Tween

可以看到上面的缓动动画组有四个原子动画组成。每一个原子动画的信息都包含在里面了。

仔细查看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属性动画的各种必要参数以及动画函数

jQuery 1.9.1源码分析系列(十五)动画处理之缓动动画核心Tween

不同的是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 全部内容就到此结束了,有问题欢迎给我留言我会在第一时间和大家取得联系的。

Javascript 相关文章推荐
用jQuery模拟页面加载进度条的实现代码
Dec 19 Javascript
无缝滚动js代码通俗易懂(自写)
Jun 19 Javascript
jQuery实现等比例缩放大图片让大图片自适应页面布局
Oct 16 Javascript
javascript模拟枚举的简单实例
Mar 06 Javascript
JavaScript中的toUTCString()方法使用详解
Jun 12 Javascript
JavaScript根据CSS的Media Queries来判断浏览设备的方法
May 10 Javascript
js html5 css俄罗斯方块游戏再现
Oct 17 Javascript
vue2 设置router-view默认路径的实例
Sep 20 Javascript
用js简单提供增删改查接口
May 12 Javascript
JS数组中对象去重操作示例
Jun 04 Javascript
vue拖拽组件 vuedraggable API options实现盒子之间相互拖拽排序
Jul 08 Javascript
快速解决layui弹窗按enter键不停弹窗的问题
Sep 18 Javascript
JS使用post提交的两种方式
Dec 03 #Javascript
JavaScript测试工具之Karma-Jasmine的安装和使用详解
Dec 03 #Javascript
五种js判断是否为整数类型方式
Dec 03 #Javascript
JavaScript学习笔记之检测客户端类型是(引擎、浏览器、平台、操作系统、移动设备)
Dec 03 #Javascript
基于javascript代码检测访问网页的浏览器呈现引擎、平台、Windows操作系统、移动设备和游戏系统
Dec 03 #Javascript
学习JavaScript设计模式(代理模式)
Dec 03 #Javascript
全面解析Bootstrap图片轮播效果
Dec 03 #Javascript
You might like
生成ubuntu自动切换壁纸xml文件的php代码
2010/07/17 PHP
PHP操作数组相关函数
2011/02/03 PHP
实例详解PHP中html word 互转的方法
2016/01/28 PHP
CI框架源码解读之利用Hook.php文件完成功能扩展的方法
2016/05/18 PHP
详细解读php的命名空间(二)
2018/02/21 PHP
php的无刷新操作实现方法分析
2020/02/28 PHP
javascript两段代码,两个小技巧
2010/02/04 Javascript
基于Jquery的简单&amp;简陋Tabs插件代码
2010/02/09 Javascript
jquery实现文本框鼠标右击无效以及不能输入的代码
2010/11/05 Javascript
javascript随机抽取0-100之间不重复的10个数
2016/02/25 Javascript
巧方法 JavaScript获取超链接的绝对URL地址
2016/06/14 Javascript
jquery自定义表单验证插件
2016/10/12 Javascript
微信小程序 九宫格实例代码
2017/01/21 Javascript
详解nodejs实现本地上传图片并预览功能(express4.0+)
2017/06/28 NodeJs
vue 全选与反选的实现方法(无Bug 新手看过来)
2018/02/09 Javascript
微信小程序上线发布流程图文详解
2019/05/06 Javascript
koa2 用户注册、登录校验与加盐加密的实现方法
2019/07/22 Javascript
Vue axios与Go Frame后端框架的Options请求跨域问题详解
2020/03/03 Javascript
微信小程序利用for循环解决内容变更问题
2020/03/05 Javascript
Python中使用PyQt把网页转换成PDF操作代码实例
2015/04/23 Python
利用Python破解斗地主残局详解
2017/06/30 Python
PyQt4实现下拉菜单可供选择并打印出来
2018/04/20 Python
Python后台开发Django会话控制的实现
2019/04/15 Python
使用python serial 获取所有的串口名称的实例
2019/07/02 Python
Python进度条的制作代码实例
2019/08/31 Python
Python和Sublime整合过程图示
2019/12/25 Python
python中数据库like模糊查询方式
2020/03/02 Python
python获取整个网页源码的方法
2020/08/03 Python
Hashtable 添加内容的方式有哪几种,有什么区别?
2012/04/08 面试题
迟到检讨书1000字
2014/01/15 职场文书
大学生个人实习的自我评价
2014/02/15 职场文书
高一学生评语大全
2014/04/25 职场文书
商场开业庆典策划方案
2014/06/02 职场文书
2014幼儿园教育教学工作总结
2014/12/17 职场文书
子女赡养老人协议书
2016/03/23 职场文书
利用Python+OpenCV三步去除水印
2021/05/28 Python