jQuery代码分析之一 Animation

本文深入剖析jQuery 1.7版本中的动画功能,详细解读animate方法的参数及内部实现机制,并探讨了支持的CSS属性及不支持的CSS属性的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

jQuery代码分析之一 Animation

本文的代码分析基于jQuery 1.7

函数jQuery.animate(params, speed, easing, callback)

params: 需要被渐变的属性及其目标值

这儿需要指出的是jQuery.fx提供了3种特殊的目标属性值:show hide toggle。例如我们可以传入{height: "show"},这样会在height属性上做值渐变来达到显示出来的效果。注意,元素必须处于hidden状态,show值才会有animation,否则直接执行complete回调函数然后结束。下面是对show/hide不同情况处理的分析

动作1动作2结果
$("#div1").hide();
  • $("#div1").animate({  width: "show",
  •     height: ["300px", "easeInQuad"] },
  •     function() { console.log("complete") });
这个时候div1元素会的width属性会从0变到初始值
  • $("#div1").animate({  width: "hide",
  •     height: ["300px", "easeOutQuad"]  }, 3000,
  •     function() { console.log("complete"); });
  • setTimeout(function() { $("#div1").stop().hide(); }, 1000);
这个时候div1元素会首先被显示出来,然后它的width属性会从1秒时候的值变到初始值
  • $("#div1").animate({  width: "hide",
  •     function() { console.log("complete"); });
这个时候div1元素会的width属性会从0变到初始值

speed: 数字或者字符串,这个参数本来是指完成整个渐变需要花的时间(以毫秒为单位),因为jQuery本身支持三种速度:slow, normal, fast,所以可以传入字符串,但是只能是刚提到的三种之一。

easing: 是在某一时刻,计算渐变属性当前值的公式,jQuery自带两个基本的easing函数:linear和swing,linear就是属性值随时间作线性变化,swing就是属性值作震荡变化,然后振幅越来越小,最后不变了,就像鸟儿的翅膀上下扇动。如果想要很cool的效果,可以使用easing插件。关于easing插件的使用,网上的例子很多,在这儿就不赘述了。但是有个东西要提一下,在jQuery UI中提供了效果(effect)函数,例如Bind,Bounce等,可以在这儿查看demo效果,原因是easing函数本身就是些原始的数学公司,让很多人觉得头大,计算二次曲线,圆弧上坐标等函数,很难从这些公式知道这个easing函数运行后是什么效果,所以要用好easing,真的不太容易。那effect函数就很直观,使用起来也方便。所以在制作动画效果时先看一下有木已经有effect函数可以满足需求,如果没有的话,那就要好好研究下easing插件了。;-) 另外,这个参数是对在params参数中提到的所有CSS属性值都用同样的easing函数,这儿就有个小问号:如果我希望对各个属性用不同的easing函数的话该怎么办呢?答案是可以在params参数中为单个属性赋easing函数,例如

1 $("#div1").animate({left: ["125px", "linear"],top: ["321px", "easeInCubic"]});

callback:animation结束时的回调函数

说了半天,本来是代码分析的,现在成演讲稿了。上代码:

  1 jQuery.extend({
  2         // 注意这儿是fx,而不是fn。fx是animation的内部实现类,
  3         // 包括animation用到的成员变量以及成员函数
  4         // fn是表示html元素的jQuery包装,就相当于设计模式中的decorator,
  5         // 因为访问html元素的属性值存在浏览器不兼容,
  6         // 所以fn就提供了一个统一的跨浏览器接口。
  7         // 这个就相当于fx的带参构造函数
  8 fx:function( elem, options, prop ) {
  9 this.options = options;
 10 this.elem = elem;
 11 this.prop = prop;
 12 
 13 options.orig = options.orig || {};
 14 }
 15 });
 1 // 这儿定义的是fx的公共成员函数
 2 jQuery.fx.prototype = {
 3 update: function() {
 4             // 调用step函数来更新元素的渐变属性值
 5         },
 6 cur: function() {
 7          // 获取元素的当前属性值,不容易理解是吧?
 8          // 参考上面fx的定义,初始化fx时需要传入一个属性名prop
 9      },
 10 custom: function(from, to, unit) {
 11             //  设置元素的属性值从from渐变到to,属性值的单位为unit
 12             // 关于unit,可以为“px” “em” "%",也可以为"",为什么呢?
 13             // 如下CSS属性是没有单位的:
 14             // fillOpacity fontWeight lineHeight 
 15             // opacity orphans widows zIndex zoom
 16             // 这些没有单位的CSS属性值放在集合jQuery.cssNumber中
 17             this.unit = unit || this.unit || ( jQuery.cssNumber[ this.prop ] ? "" : "px" );
 18 
 19             // 里面定义了一个闭包函数,它可以看作是step函数的包装类,
 20             // step函数在下面定义的
 21             function t( gotoEnd ) {
 22                // 注意到self了吧?这个地方有个小技巧,
 23                // 调用t时上下文(context)可能会改变,
 24                 // 所以之前会把指向fx的this保存到self中,
 25                 // 那这样才能保证调用到fx的step函数了。
 26                 // 否则就有可能报"找不到step函数"的错误
 27                 return self.step( gotoEnd );
 28             }
 29             // 设置step包装类的成员变量
 30             t.queue = this.options.queue;
 31             // step包装类的成员函数saveState很有趣,
 32             // 它只有当hide值为true并且元素没有名为
 33             // "fxshow"+self.prop的附加属性值时
 34             // 才会做一件事:保存start值。这里面有几层含义,
 35             // 一是只有在调用了fx.hide(),saveState才起作用,
 36             // 下面在介绍hide()定义时,将会看到这一点;
 37             // 二是只有头一次调用saveState会起作用,
 38             // 因为后面调用时附加属性值已经不为undefined了。
 39             // 这个函数是为了处理这样一种情况:当hide的过程还没完成时
 40             // 调用stop来立即停止animation,这个时候我们需要保存元素的状态,
 41             // 可以参考上面提到的show/hide的不同情况的处理2
 42             t.saveState = function() {
 43                 if ( self.options.hide && jQuery._data( self.elem, "fxshow" + self.prop ) === undefined ) {
 44                     jQuery._data( self.elem, "fxshow" + self.prop, self.start );
 45                 }
 46             };
 47 
 48             // 从这儿我们可以看出animation的基本实现机制还是依赖于强大的setInternal。
 49             // 集合timers里的对象就是刚才提到的step函数的包装类,
 50             // 每隔一段时间调用一下这些包装类来更新元素的属性值。
 51             if ( t() && jQuery.timers.push(t) && !timerId ) {
 52                 timerId = setInterval( fx.tick, fx.interval );
 53             }
 54         },
 55 show: function() {
 56           // 当需要被animate的CSS属性值为show时,处理这种情况,
 57           // 最后仍然是调用custom函数,只不过有些参数是特殊值
 58           if ( dataShow !== undefined ) {
 59               // This show is picking up where a previous hide or show left off
 60               this.custom( this.cur(), dataShow );
 61           } else {
 62               this.custom( this.prop === "width" || this.prop === "height" ? 1 : 0, this.cur() );
 63           }
 64       },
 65 hide: function() {
 66           // 当需要被animate的CSS属性值为hide时,处理这种情况,
 67           // 最后仍然是调用custom函数,只不过有些参数是特殊值
 68           this.custom( this.cur(), 0 );
 69       },
 70 step: function( gotoEnd ) {
 71           // 这个函数就是每次internal后的回调函数,更新元素的属性值,
 72           // 如果animation已经结束,需要做一些清理工作
 73       }
 74 };
 1 jQuery.extend(jQuery.fx, {
 2 tick: function() {
 3 var timers = jQuery.timers;
 4 // 这个地方会调用所有的fx.step函数来更新元素的被animated的属性值
 5 // 至于是怎么调到fx.step的,上面的代码分析里有提到
 6 // 属性的值已经到了目标值,那就将其对应的step函数从timers中删除
 7 // 这个地方用到了JavaScript中一个很cool的语法:
 8 // 可以在轮询集合时,把元素从集合中删掉
 9 // 如果对C#熟悉的同学应该清楚,这种方式在C#中是要报异常的
 10 for (var i = 0; i < timers.length; i++)
11 if (!timers[i]()) timers.splice(i--, 1);
12 //如果timers中已经没有未完成的属性值未达到目标值,
13 // 那就把这个用setInterval启动的timer取消掉
14 if (!timers.length) jQuery.fx.stop();
15 },
16 interval: 13,// 定义setInterval的时间间隔
17 stop: function() {
18 // 这个应该很熟悉吧?;-)就不介绍了
19 // 不熟悉的同学可以搜索一下
20     clearInternal(timerId);
21     timerId = null;
22 },
23     // 定义默认的animation所需要的时间
24 speeds: {
25 slow: 600,
26       fast: 200,
27       _default: 400
28         },
29         // 注意这儿也有个step成员变量,但是是个匿名对象
30         // 他主要负责改变元素的属性值,我们知道一旦元素的属性值被修改,
31         // 浏览器的render engine都会重绘页面,这样的修改甚至会
32         // 影响到页面布局,所以最好不要把大量计算和属性值操作夹杂在一起,
33         // 很容易引起animation显示不流畅,也就是会“看起来很卡”
34 step: {
35 opacity: function(fx) {
36              jQuery.style(fx.elem, "opacity", fx.now);
37          },
38 _default: function(fx) {
39               if (fx.elem.style && fx.elem.style[fx.prop] != null)
40                   fx.elem.style[fx.prop] = fx.now + fx.unit;
41               else fx.elem[fx.prop] = fx.now;
42           }
43       }
44 });

问题

animate支持的CSS属性:
  • 拥有数值,例如width, height, zoom; 下表列出的是目前FixFox支持的所有可以通过CSS的keyframe新特性能animate的属性,但jQuery默认并不支持所有这些属性
    Property TypeProperty NameTransitionable Values
    Text propertiescolorcolor
    font-sizelength, percentage
    font-weightnumber, keywords(excluding bolder, lighter))
    letter-spacinglength
    line-heightnumber, length, percentage
    text-indentlength, percentage
    text-shadowshadow
    vertical-alignkeywords, length, percentage
    word-spacinglength, percentage
    Box propertiesbackground-colorcolor
    background-imageimages, gradients
    background-positionpercentage, length
    border-left-colorcolor
    border-spacinglength
    border-left-widthlength
    cliprectangle
    croprectangle
    margin-leftlength
    opacitynumber
    outline-widthlength
    outline-offsetinteger
    outline-colorcolor
    padding-leftlength
    width, min-width, max-widthlength, percentage
    Positioning propertiesbottomlength, percentage
    toplength, percentage
    grid-*various
    leftlength, percentage
    rightlength, percentage
    visibilityvisibility
    z-indexinteger
    zoomnumber
    SVG propertiesfillpaint server
    fill-opacityfloat
    flood-colorcolor, keywords
    lighting-colorcolor, keywords
    marker-offsetlength
    stop-colorcolor
    stop-opacityfloat
    strokepaint server
    stroke-dasharraylist of numbers
    stroke-dashoffsetnumber
    stroke-miterlimitnumber
    stroke-opacityfloat
    stroke-widthfloat
    viewport-fillcolor
    viewport-fill-opacitycolor
animate不支持的CSS属性:
  • 拥有非数值,例如background-color

    解决方案:使用jQuery插件color

  • shortcut CSS属性,例如font, border

    解决方案:使用非shotcut写法,例如我们想对font-size做animate,可以直接设置属性font-size而不是font

  • CSS3的新增属性,例如box-shadow, transform

    解决方案:使用transit插件

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值