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实现异步刷新的代码(转载)
Mar 29 Javascript
自定义一个jquery插件[鼠标悬浮时候 出现说明label]
Jun 27 Javascript
JS事件Event元素(兼容IE,Firefox,Chorme)
Nov 01 Javascript
js定时器的使用(实例讲解)
Jan 06 Javascript
分析了一下JQuery中的extend方法实现原理
Feb 27 Javascript
javascript省市区三级联动下拉框菜单实例演示
Nov 29 Javascript
javascript精确统计网站访问量实例代码
Dec 19 Javascript
Angular中$compile源码分析
Jan 28 Javascript
js简单实现网页换肤功能
Apr 07 Javascript
jquery实现侧边栏左右伸缩效果的示例
Dec 19 jQuery
详解vue-cli 构建项目 vue-cli请求后台接口 vue-cli使用axios、sass、swiper
May 28 Javascript
vue实现城市列表选择功能
Jul 16 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
百度地图经纬度转换到腾讯地图/Google 对应的经纬度
2015/08/28 PHP
php示例详解Constructor Prototype Pattern 原型模式
2015/10/15 PHP
Yii2.0预定义的别名功能小结
2016/07/04 PHP
PHP单链表的实现代码
2016/07/05 PHP
PHP判断JSON对象是否存在的方法(推荐)
2016/07/06 PHP
ExtJS 2.0 实用简明教程之布局概述
2009/04/29 Javascript
jQuery学习笔记(4)--Jquery中获取table中某列值的具体思路
2013/04/10 Javascript
用innerhtml提高页面打开速度的方法
2013/08/02 Javascript
Js 去掉字符串中的空格(实现代码)
2013/11/19 Javascript
用jquery修复在iframe下的页面锚点失效问题
2014/08/22 Javascript
jQuery使用fadein方法实现渐出效果实例
2015/03/27 Javascript
javascript中indexOf技术详解
2015/05/07 Javascript
jQuery使用$.each遍历json数组的简单实现方法
2016/04/18 Javascript
JS图片等比例缩放方法完整示例
2016/08/03 Javascript
清除js缓存的多种方法总结
2016/12/09 Javascript
浅谈原生JS中的延迟脚本和异步脚本
2017/07/12 Javascript
iscroll实现下拉刷新功能
2017/07/18 Javascript
Vue仿今日头条实例详解
2018/02/06 Javascript
谈谈JavaScript中super(props)的重要性
2019/02/12 Javascript
vue 实现特定条件下绑定事件
2019/11/09 Javascript
如何使用webpack打包一个库library的方法步骤
2019/12/18 Javascript
[03:36]2015国际邀请赛第二日现场精彩集锦
2015/08/06 DOTA
[42:25]2018DOTA2亚洲邀请赛 4.5 淘汰赛 LGD vs Liquid 第三场
2018/04/06 DOTA
[32:17]完美世界DOTA2联赛循环赛LBZS vs Forest第二场 10月30日
2020/10/31 DOTA
使用rpclib进行Python网络编程时的注释问题
2015/05/06 Python
Python中的条件判断语句基础学习教程
2016/02/07 Python
Python之列表实现栈的工作功能
2019/01/28 Python
Django框架模板文件使用及模板文件加载顺序分析
2019/05/23 Python
python logging设置level失败的解决方法
2020/02/19 Python
详细分析Python可变对象和不可变对象
2020/07/09 Python
SKECHERS斯凯奇中国官网:来自美国的运动休闲品牌
2018/11/14 全球购物
欧姆龙医疗保健与医疗产品:Omron Healthcare
2020/02/10 全球购物
请说出以下代码输出什么
2013/08/30 面试题
大学生感恩父母演讲稿
2014/08/28 职场文书
党员组织生活会发言材料
2014/10/17 职场文书
公司年夜饭通知
2015/04/25 职场文书