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 相关文章推荐
javascript与CSS复习(二)
Jun 29 Javascript
打豆豆小游戏 用javascript编写的[打豆豆]小游戏
Jan 08 Javascript
框架页面高度自动刷新的Javascript脚本
Nov 01 Javascript
jQuery获取对象简单实现方法小结
Oct 30 Javascript
jQuery插件slides实现无缝轮播图特效
Apr 17 Javascript
jquery 重写 ajax提交并判断权限后 使用load方法报错解决方法
Jan 19 Javascript
javascript瀑布流式图片懒加载实例解析与优化
Feb 23 Javascript
jquery基础知识第一讲之认识jquery
Mar 17 Javascript
实现easyui的datagrid导出为excel的示例代码
Nov 10 Javascript
JS实现小球的弹性碰撞效果
Nov 11 Javascript
node.js 模块和其下载资源的镜像设置的方法
Sep 06 Javascript
JS实现随机点名器
Apr 12 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
MOTOROLA 摩托罗拉 MODEL 66-XI五灯中波收音机
2021/03/02 无线电
PHP排序算法的复习和总结
2012/02/15 PHP
php生成EAN_13标准条形码实例
2013/11/13 PHP
php实现生成带二维码图片并强制下载功能
2018/02/24 PHP
清华大学出版的事半功倍系列 javascript全部源代码
2007/05/04 Javascript
JavaScript 全角转半角部分
2009/10/28 Javascript
JS Range HTML文档/文字内容选中、库及应用介绍
2011/05/12 Javascript
js页面滚动时层智能浮动定位实现(jQuery/MooTools)
2011/08/23 Javascript
JavaScript中访问节点对象的方法有哪些如何使用
2013/09/24 Javascript
js生成动态表格并为每个单元格添加单击事件的方法
2014/04/14 Javascript
JavaScript的jQuery库中function的存在和参数问题
2015/08/13 Javascript
jQuery实现图片左右滚动特效
2020/04/20 Javascript
jQuery 实现评论等级好评差评特效
2016/05/06 Javascript
深入理解Node.js的HTTP模块
2016/10/12 Javascript
微信小程序 Toast自定义实例详解
2017/01/20 Javascript
jquery select插件异步实时搜索实例代码
2017/10/20 jQuery
vue中将html字符串转换成html后遇到的问题小结
2018/12/10 Javascript
详解vue-cli@2.x项目迁移日志
2019/06/06 Javascript
[02:20]DOTA2英雄基础教程 黑暗贤者
2013/12/19 DOTA
[42:20]2014 DOTA2华西杯精英邀请赛5 24 DK VS NewBee
2014/05/25 DOTA
flask入门之文件上传与邮件发送示例
2018/07/18 Python
Python远程视频监控程序的实例代码
2019/05/05 Python
pandas取出重复数据的方法
2019/07/04 Python
python flask中动态URL规则详解
2019/11/22 Python
pytorch中的transforms模块实例详解
2019/12/31 Python
信号生成及DFT的python实现方式
2020/02/25 Python
Python脚本实现监听服务器的思路代码详解
2020/05/28 Python
旅游个人求职信范文
2014/01/30 职场文书
党员岗位承诺书
2014/03/25 职场文书
招商引资工作汇报
2014/10/28 职场文书
创业计划书之面包店
2019/09/12 职场文书
2019升学宴主持词范本5篇
2019/10/09 职场文书
python tkinter模块的简单使用
2021/04/07 Python
MySQL之select、distinct、limit的使用
2021/11/11 MySQL
Vertica集成Apache Hudi重磅使用指南
2022/03/31 Servers
Redis分布式锁的7种实现
2022/04/01 Redis