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的树型插件(OrangeTree)使用介绍
May 03 Javascript
Ajax执行顺序流程及回调问题分析
Dec 10 Javascript
一个简单的弹性返回顶部JS代码实现介绍
Jun 09 Javascript
JS简单设置下拉选择框默认值的方法
Aug 20 Javascript
jQuery的 $.ajax防止重复提交的两种方法(推荐)
Oct 14 Javascript
微信小程序页面开发注意事项整理
May 18 Javascript
angular中ui calendar的一些使用心得(推荐)
Nov 03 Javascript
Node.js中,在cmd界面,进入退出Node.js运行环境的方法
May 12 Javascript
详解微信小程序实现WebSocket心跳重连
Jul 31 Javascript
详解Vue CLI3配置解析之css.extract
Sep 14 Javascript
JS 音频可视化插件Wavesurfer.js的使用教程
Oct 31 Javascript
小程序自定义弹框效果
Nov 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
DC这些乐高系列动画电影你看过几部?
2020/04/09 欧美动漫
深入PHP与浏览器缓存的分析
2013/06/03 PHP
PHP获取Exif缩略图的方法
2015/07/13 PHP
javascript window.confirm确认 取消对话框实现代码小结
2012/10/21 Javascript
解决Extjs 4 Panel作为Window组件的子组件时出现双重边框问题
2013/01/11 Javascript
JS实现遮罩层效果的简单实例
2013/11/12 Javascript
从数组中随机取x条不重复数据的JS代码
2013/12/24 Javascript
Node.js操作mysql数据库增删改查
2016/03/30 Javascript
前端框架Vue.js中Directive知识详解
2016/09/12 Javascript
bootstrap如何让dropdown menu按钮式下拉框长度一致
2017/04/10 Javascript
基于Jquery Ajax type的4种类型(详解)
2017/08/02 jQuery
vue-infinite-loading2.0 中文文档详解
2018/04/08 Javascript
vue+element UI实现树形表格带复选框的示例代码
2019/04/16 Javascript
微信公众号获取用户地理位置并列出附近的门店的示例代码
2019/07/25 Javascript
[02:51]DOTA2 2015国际邀请赛中国区预选赛第一日战报
2015/05/27 DOTA
Go语言基于Socket编写服务器端与客户端通信的实例
2016/02/19 Python
Python2.x利用commands模块执行Linux shell命令
2016/03/11 Python
基于DATAFRAME中元素的读取与修改方法
2018/06/08 Python
Python 3.x 判断 dict 是否包含某键值的实例讲解
2018/07/06 Python
python3 读取Excel表格中的数据
2018/10/16 Python
python 去除二维数组/二维列表中的重复行方法
2019/01/23 Python
Python解压 rar、zip、tar文件的方法
2019/11/19 Python
Python面向对象之继承原理与用法案例分析
2019/12/31 Python
python 解决selenium 中的 .clear()方法失效问题
2020/09/01 Python
python 基于Apscheduler实现定时任务
2020/12/15 Python
解决PyCharm无法使用lxml库的问题(图解)
2020/12/22 Python
苹果美国官方商城:Apple美国
2016/08/24 全球购物
美国专注于健康商品的网站:eVitamins
2017/01/23 全球购物
英国亚马逊官方网站:Amazon.co.uk
2019/08/09 全球购物
写好自荐信的要点
2013/11/06 职场文书
学生党员思想汇报范文
2014/01/09 职场文书
电大毕业自我鉴定
2014/02/03 职场文书
大专生找工作自荐书
2014/06/10 职场文书
学校党风廉政建设调研报告
2015/01/01 职场文书
大学生社会实践感想
2015/08/11 职场文书
Pytorch distributed 多卡并行载入模型操作
2021/06/05 Python