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跨Iframe选择实现代码
Aug 19 Javascript
判断文档离浏览器顶部的距离的方法
Jan 08 Javascript
JavaScript事件委托的技术原理探讨示例
Apr 17 Javascript
jQuery修改CSS伪元素属性的方法
Jul 30 Javascript
加载列表时jquery获取ul中第一个li的属性
Nov 02 Javascript
jQuery EasyUI中的日期控件DateBox修改方法
Nov 09 Javascript
JavaScript原生编写《飞机大战坦克》游戏完整实例
Jan 04 Javascript
jquery 校验中国身份证号码实例详解
Apr 11 jQuery
javascript如何用递归写一个简单的树形结构示例
Sep 06 Javascript
阿里大于短信验证码node koa2的实现代码(最新)
Sep 07 Javascript
Angular中的ng-template及angular 使用ngTemplateOutlet 指令的方法
Aug 08 Javascript
LayUi数据表格自定义赋值方式
Oct 26 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
使用PHP制作新闻系统的思路
2006/10/09 PHP
9个PHP开发常用功能函数小结
2011/07/15 PHP
php版阿里大于(阿里大鱼)短信发送实例详解
2016/11/30 PHP
PHP 二维关联数组根据其中一个字段排序(推荐)
2017/04/04 PHP
jQuery学习笔记 更改jQuery对象
2012/09/19 Javascript
jQuery Ajax调用WCF服务详细教程
2015/03/31 Javascript
js兼容火狐显示上传图片预览效果的方法
2015/05/21 Javascript
jQuery实现导航滚动到指定内容效果完整实例【附demo源码下载】
2016/09/20 Javascript
JS 实现可停顿的垂直滚动实例代码
2016/11/23 Javascript
ionic开发中点击input时键盘自动弹出
2016/12/23 Javascript
Extjs表单输入框异步校验的插件实现方法
2017/03/20 Javascript
微信小程序 自动登陆PHP源码实例(源码下载)
2017/05/08 Javascript
HTML5开发Kinect体感游戏的实例应用
2017/09/18 Javascript
Phaser.js实现简单的跑酷游戏附源码下载
2018/10/26 Javascript
使用p5.js临摹动态图形
2019/10/23 Javascript
js实现简单的日历显示效果函数示例
2019/11/25 Javascript
[01:03:36]Ti4 循环赛第三日DK vs Titan
2014/07/12 DOTA
用Python编写一个简单的Lisp解释器的教程
2015/04/03 Python
python 分离文件名和路径以及分离文件名和后缀的方法
2018/10/21 Python
在python带权重的列表中随机取值的方法
2019/01/23 Python
深入了解Python 变量作用域
2020/07/24 Python
Restful_framework视图组件代码实例解析
2020/11/17 Python
使用Python判断一个文件是否被占用的方法教程
2020/12/16 Python
时装界的“朋克之母”:Vivienne Westwood
2017/07/06 全球购物
Koral官方网站:女性时尚运动服
2019/04/10 全球购物
大学毕业生通用自我评价
2014/01/05 职场文书
国庆节文艺活动方案
2014/02/03 职场文书
法律进机关实施方案
2014/03/12 职场文书
父母对孩子的寄语
2014/04/09 职场文书
公司总经理助理岗位职责
2014/07/09 职场文书
夫妻忠诚协议范文
2014/11/16 职场文书
2014年环保局工作总结
2014/12/11 职场文书
村官个人总结范文
2015/03/03 职场文书
三严三实学习心得体会(精选N篇)
2016/01/05 职场文书
比较node.js和Deno
2021/04/27 Javascript
MySQL数据库完全卸载的方法
2022/03/03 MySQL