jquery fx 源码

  1. /*  
  2.  * author:prk date:2008-08-07 comment:analyse the fx of jQuery.  
  3.  *   
  4.  */  
  5. jQuery.fn.extend({   
  6.        
  7.     // show(speed,[callback])   
  8.     // 以优雅的动画隐藏所有匹配的元素,并在显示完成后可选地触发一个回调函数。   
  9.     // 可以根据指定的速度动态地改变每个匹配元素的高度、宽度和不透明度。   
  10.     // 显示隐藏的匹配元素 show()   
  11.     show: function(speed,callback){   
  12.         return speed ?   
  13.             this.animate({   
  14.                 height: "show", width: "show", opacity: "show"  
  15.             }, speed, callback) :   
  16.   
  17.             this.filter(":hidden").each(function(){   
  18.                 this.style.display = this.oldblock || "";   
  19.                 if ( jQuery.css(this,"display") == "none" ) {   
  20.                     var elem = jQuery("<" + this.tagName + " />").appendTo("body");   
  21.                     this.style.display = elem.css("display");// 默认的显示的display   
  22.                     // handle an edge condition where css is - div {   
  23.                     // display:none; } or similar   
  24.                     if (this.style.display == "none")// 处理显式地设定了该tag不显示,只好采用b   
  25.                         this.style.display = "block";   
  26.                     elem.remove();// 上面这些的处理有没有必要呢?   
  27.                 }   
  28.             }).end();// 回到前一个jQuery对象   
  29.     },   
  30.        
  31.     // 与show相反   
  32.     hide: function(speed,callback){   
  33.         return speed ?   
  34.             this.animate({   
  35.                 height: "hide", width: "hide", opacity: "hide"  
  36.             }, speed, callback) :   
  37.   
  38.             this.filter(":visible").each(function(){   
  39.                 this.oldblock = this.oldblock || jQuery.css(this,"display");   
  40.                 this.style.display = "none";   
  41.             }).end();   
  42.     },   
  43.   
  44.     // Save the old toggle function   
  45.     _toggle: jQuery.fn.toggle,   
  46.         
  47.     // 切换元素的可见状态。   
  48.     // 如果元素是可见的,切换为隐藏的;如果元素是隐藏的,切换为可见的。   
  49.        
  50.     // 每次点击后依次调用函数。   
  51.     // 如果点击了一个匹配的元素,则触发指定的第一个函数,当再次点击同一元素时,则触发指定的第二个函数,   
  52.     // 如果有更多函数,则再次触发,直到最后一个。随后的每次点击都重复对这几个函数的轮番调用。   
  53.     // 可以使用unbind("click")来删除。   
  54.     toggle: function( fn, fn2 ){   
  55.         return jQuery.isFunction(fn) && jQuery.isFunction(fn2) ?   
  56.             this._toggle.apply( this, arguments ) :// 原来的toggle   
  57.             (fn ?   
  58.                this.animate({height: "toggle", width: "toggle", opacity: "toggle"}, fn, fn2)   
  59.             :  this.each(function(){jQuery(this)[ jQuery(this).is(":hidden") ? "show" : "hide" ]();}   
  60.             // 对每个元素都调用show,或hide函数。   
  61.             )   
  62.         );   
  63.     },   
  64.   
  65.     // 把所有匹配元素的不透明度以渐进方式调整到指定的不透明度,并在动画完成后可选地触发一个回调函数。   
  66.      // 这个动画只调整元素的不透明度,也就是说所有匹配的元素的高度和宽度不会发生变化。   
  67.     fadeTo: function(speed,to,callback){   
  68.         return this.animate({opacity: to}, speed, callback);   
  69.     },   
  70.        
  71.     /**  
  72.      * 用于创建自定义动画的函数。  
  73.      * 这个函数的关键在于指定动画形式及结果样式属性对象。这个对象中每个属性都表示一个可以变化的样式属性(如“height”、“top”或“opacity”)。  
  74.      * 注意:所有指定的属性必须用骆驼形式,比如用marginLeft代替margin-left.  
  75.      * 而每个属性的值表示这个样式属性到多少时动画结束。如果是一个数值,样式属性就会从当前的值渐变到指定的值。如果使用的是“hide”、“show”或“toggle”这样的字符串值,则会为该属性调用默认的动画形式。  
  76.      * 在 jQuery 1.2 中,你可以使用 em 和 % 单位。另外,在 jQuery 1.2 中,你可以通过在属性值前面指定 "+=" 或  
  77.      * "-=" 来让元素做相对运动。  
  78.      *   
  79.      * params (Options) : 一组包含作为动画属性和终值的样式属性和及其值的集合 。 duration (String,Number)  
  80.      * :(可选) 三种预定速度之一的字符串("slow", "normal", or "fast")或表示动画时长的毫秒数值(如:1000)  
  81.      * easing (String) : (可选) 要使用的擦除效果的名称(需要插件支持).默认jQuery提供"linear" 和 "swing".  
  82.      * callback (Function) : (可选) 在动画完成时执行的函数  
  83.      */  
  84.     animate: function( prop, speed, easing, callback ) {   
  85.         var optall = jQuery.speed(speed, easing, callback);   
  86.   
  87.         return this[ optall.queue === false ? "each" : "queue" ](function(){// 执行each或queue方法   
  88.             var opt = jQuery.extend({}, optall), p,   
  89.                 hidden = this.nodeType == 1 && jQuery(this).is(":hidden"),// 是元素节点且是隐藏的   
  90.                 self = this;// 当前的元素   
  91.        
  92.             for ( p in prop ) {   
  93.                 if ( prop[p] == "hide" && hidden || prop[p] == "show" && !hidden )// 已经是完成的状态   
  94.                     return opt.complete.call(this);// 调用complate函数,在用户的callback加上队列的处理   
  95.   
  96.                 if ( ( p == "height" || p == "width" ) && this.style ) {// style中高度,宽度   
  97.                     opt.display = jQuery.css(this"display");// 保存当前元素的display   
  98.                     opt.overflow = this.style.overflow;// 保证没有暗中进行的   
  99.                 }   
  100.             }   
  101.             if ( opt.overflow != null )// 超出部分不见   
  102.                 this.style.overflow = "hidden";   
  103.   
  104.             opt.curAnim = jQuery.extend({}, prop);   
  105.       
  106.             jQuery.each( prop, function(name, val){// 对当前元素的给定的属性进行变化的操作   
  107.                 var e = new jQuery.fx( self, opt, name );   
  108.   
  109.                 if ( /toggle|show|hide/.test(val) )// 传参的属性可以用toggle,show,hide,其它   
  110.                 // 调用当前e.show,e.hide,e.val的方法,jQuery.fx.prototype   
  111.                     e[ val == "toggle" ? hidden ? "show" : "hide" : val ]( prop );                     
  112.                 else {// 支持"+=" 或 "-=" 来让元素做相对运动。   
  113.                     var parts = val.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/),   
  114.                         start = e.cur(true) || 0;// 当前的大小或0   
  115.   
  116.                     if ( parts ) {   
  117.                         var end = parseFloat(parts[2]),// 值   
  118.                             unit = parts[3] || "px";// 单位   
  119.                            
  120.                         if ( unit != "px" ) {// 计算开始的值=(end/cur)*start   
  121.                             self.style[ name ] = (end || 1) + unit;   
  122.                             start = ((end || 1) / e.cur(true)) * start;   
  123.                             self.style[ name ] = start + unit;   
  124.                         }   
  125.   
  126.                         if ( parts[1] )// +=/-=,做相对运行   
  127.                             end = ((parts[1] == "-=" ? -1 : 1) * end) + start;   
  128.   
  129.                         e.custom( start, end, unit );// 动画   
  130.                     } else  
  131.                         e.custom( start, val, "" );// 动画   
  132.                 }   
  133.             });   
  134.             // For JS strict compliance   
  135.             return true;   
  136.         });   
  137.     },   
  138.   
  139.     // 实现队列操作,为jQuery对象中的每个元素都加type的属性,值为fn.   
  140.     queue: function(type, fn){   
  141.         // 可能看出支持一个fn的参数的形式,支持fn的array集形式   
  142.         if ( jQuery.isFunction(type) || ( type && type.constructor == Array )) {   
  143.             fn = type;   
  144.             type = "fx";   
  145.         }   
  146.         // type不存在,空字符等,无参数,type:string,fn不存在。肯定不是函数,也不是数组   
  147.         if ( !type || (typeof type == "string" && !fn) )   
  148.             return queue( this[0], type );   
  149.   
  150.         return this.each(function(){   
  151.             if ( fn.constructor == Array )// 数组的形式   
  152.                 queue(this, type, fn);// 存储在元素的type属性中   
  153.             else {   
  154.                 queue(this, type).push( fn );// 加上一个   
  155.   
  156.                 if ( queue(this, type).length == 1 )   
  157.                     fn.call(this);   
  158.             }   
  159.         });   
  160.     },   
  161.   
  162.     stop: function(clearQueue, gotoEnd){   
  163.         var timers = jQuery.timers;   
  164.   
  165.         if (clearQueue)   
  166.             this.queue([]);// 清除   
  167.   
  168.         this.each(function(){   
  169.             // go in reverse order so anything added to the queue during the   
  170.             // loop is ignored   
  171.             for ( var i = timers.length - 1; i >= 0; i-- )   
  172.                 if ( timers[i].elem == this ) {   
  173.                     if (gotoEnd)   
  174.                         // force the next step to be the last   
  175.                         timers[i](true);   
  176.                     timers.splice(i, 1);   
  177.                 }   
  178.         });   
  179.   
  180.         // start the next in the queue if the last step wasn't forced   
  181.         if (!gotoEnd)   
  182.             this.dequeue();   
  183.   
  184.         return this;   
  185.     }   
  186.   
  187. });   
  188.   
  189. // Generate shortcuts for custom animations   
  190. jQuery.each({   
  191.     slideDown: { height:"show" },   
  192.     slideUp: { height: "hide" },   
  193.     slideToggle: { height: "toggle" },   
  194.     fadeIn: { opacity: "show" },   
  195.     fadeOut: { opacity: "hide" }   
  196. }, function( name, props ){   
  197.     jQuery.fn[ name ] = function( speed, callback ){   
  198.         return this.animate( props, speed, callback );   
  199.     };   
  200. });   
  201.   
  202. // 为元素加上type的array的属性,或返回取到elem上type的值   
  203. var queue = function( elem, type, array ) {   
  204.     if ( elem ){   
  205.         type = type || "fx";   
  206.         var q = jQuery.data( elem, type + "queue" );   
  207.         if ( !q || array )   
  208.             q = jQuery.data( elem, type + "queue", jQuery.makeArray(array) );   
  209.     }   
  210.     return q;   
  211. };   
  212. // 出列,根据type   
  213. jQuery.fn.dequeue = function(type){   
  214.     type = type || "fx";   
  215.     return this.each(function(){   
  216.         var q = queue(this, type);// 得取type的的值   
  217.         q.shift();// 移出一个   
  218.         if ( q.length )   
  219.             q[0].call( this );   
  220.     });   
  221. };   
  222.   
  223. jQuery.extend({   
  224.      // 主要用于辅助性的工作   
  225.     speed: function(speed, easing, fn) {   
  226.         var opt = speed && speed.constructor == Object ? speed : {// 采用紧凑型方式   
  227.             complete: fn || !fn && easing ||   
  228.                 jQuery.isFunction( speed ) && speed,// coplete是至多三个参数的最后一个,当然是Fn.   
  229.             duration: speed,// 持继的时间   
  230.             easing: fn && easing || easing && easing.constructor != Function && easing// 不是Fn   
  231.         };   
  232.   
  233.         opt.duration = (opt.duration && (opt.duration.constructor == Number ?   
  234.             opt.duration :  jQuery.fx.speeds[opt.duration])) // 存在,不是数值,转找   
  235.             || jQuery.fx.speeds._default;// 默认的   
  236.   
  237.         // Queueing   
  238.         opt.old = opt.complete;   
  239.         opt.complete = function(){// 排队的处理   
  240.             if ( opt.queue !== false )   
  241.                 jQuery(this).dequeue();   
  242.             if ( jQuery.isFunction( opt.old ) )   
  243.                 opt.old.call( this );   
  244.         };   
  245.   
  246.         return opt;   
  247.     },   
  248.   
  249.     // 擦除效果   
  250.     easing: {   
  251.         linear: function( p, n, firstNum, diff ) {   
  252.             return firstNum + diff * p;   
  253.         },   
  254.         swing: function( p, n, firstNum, diff ) {   
  255.             return ((-Math.cos(p*Math.PI)/2) + 0.5) * diff + firstNum;   
  256.         }   
  257.     },   
  258.   
  259.     timers: [],// jQuery.timers   
  260.     timerId: null,   
  261.        
  262.     // 根据参数构成一个对象   
  263.     fx: function( elem, options, prop ){   
  264.         this.options = options;   
  265.         this.elem = elem;   
  266.         this.prop = prop;   
  267.   
  268.         if ( !options.orig )   
  269.             options.orig = {};   
  270.     }   
  271.   
  272. });   
  273.   
  274. jQuery.fx.prototype = {   
  275.   
  276.     // 为元素设值,更新显示   
  277.     update: function(){   
  278.         if ( this.options.step )   
  279.             this.options.step.call( this.elem, this.now, this );   
  280.   
  281.         (jQuery.fx.step[this.prop] || jQuery.fx.step._default)( this );// 为元素的设值,fx.prop   
  282.   
  283.         // 对于高度和宽度,采用display=block的形式。   
  284.         if ( ( this.prop == "height" || this.prop == "width" ) && this.elem.style )   
  285.             this.elem.style.display = "block";   
  286.     },   
  287.   
  288.     // 当前元素当前属性的值   
  289.     cur: function(force){   
  290.         if ( this.elem[this.prop] != null && (!this.elem.style || this.elem.style[this.prop] == null) )   
  291.             return this.elem[ this.prop ];   
  292.   
  293.         var r = parseFloat(jQuery.css(this.elem, this.prop, force));   
  294.         return r && r > -10000 ? r : parseFloat(jQuery.curCSS(this.elem, this.prop)) || 0;   
  295.     },   
  296.   
  297.     // 开动一个动画   
  298.     custom: function(from, to, unit){   
  299.         this.startTime = now();   
  300.         this.start = from;   
  301.         this.end = to;   
  302.         this.unit = unit || this.unit || "px";   
  303.         this.now = this.start;   
  304.         this.pos = this.state = 0;   
  305.         this.update();   
  306.   
  307.         var self = this;   
  308.         function t(gotoEnd){   
  309.             return self.step(gotoEnd);// 调用step(gotoEnd)//本对象的   
  310.         }   
  311.         t.elem = this.elem;   
  312.         jQuery.timers.push(t);   
  313.             
  314.         // 第一次,或上一次已经把jQuery.timers全部执行完了。   
  315.         if ( jQuery.timerId == null ) {   
  316.             jQuery.timerId = setInterval(function(){   
  317.                 var timers = jQuery.timers;   
  318.                 for ( var i = 0; i < timers.length; i++ )// 执行timers中所有   
  319.                     if ( !timers[i]() )// 执行了一次,就从timers中除去   
  320.                         timers.splice(i--, 1);   
  321.   
  322.                 if ( !timers.length ) {// length==0,取消Interval   
  323.                     clearInterval( jQuery.timerId );   
  324.                     jQuery.timerId = null;   
  325.                 }   
  326.             }, 13);   
  327.         }   
  328.     },   
  329.   
  330.     // Simple 'show' function   
  331.     show: function(){   
  332.         // 保存当前的,以被修改之后能得到初始的值   
  333.         this.options.orig[this.prop] = jQuery.attr( this.elem.style, this.prop );   
  334.         this.options.show = true;   
  335.            
  336.         this.custom(0this.cur());   
  337.   
  338.         // Make sure that we start at a small width/height to avoid any   
  339.         // flash of content   
  340.         if ( this.prop == "width" || this.prop == "height" )   
  341.             this.elem.style[this.prop] = "1px";   
  342.   
  343.         // 开始显示元素   
  344.         jQuery(this.elem).show();   
  345.     },   
  346.   
  347.     // 隐藏   
  348.     hide: function(){   
  349.         // 保存当前的,以被修改之后能得到初始的值   
  350.         this.options.orig[this.prop] = jQuery.attr( this.elem.style, this.prop );   
  351.         this.options.hide = true;   
  352.            
  353.         this.custom(this.cur(), 0);   
  354.     },   
  355.   
  356.     // 动画的每一个步骤   
  357.     step: function(gotoEnd){   
  358.         var t = now();   
  359.          // 结束或当前时间大于startTime+duration   
  360.         if ( gotoEnd || t > this.options.duration + this.startTime ) {   
  361.             this.now = this.end;   
  362.             this.pos = this.state = 1;   
  363.             this.update();   
  364.   
  365.             this.options.curAnim[ this.prop ] = true;   
  366.   
  367.             var done = true;   
  368.             for ( var i in this.options.curAnim )   
  369.                 if ( this.options.curAnim[i] !== true )   
  370.                     done = false;   
  371.   
  372.             if ( done ) {// 重置所有的设定   
  373.                 if ( this.options.display != null ) {// Reset the overflow   
  374.                     this.elem.style.overflow = this.options.overflow;   
  375.                     // Reset the display   
  376.                     this.elem.style.display = this.options.display;   
  377.                     if ( jQuery.css(this.elem, "display") == "none" )   
  378.                         this.elem.style.display = "block";   
  379.                 }   
  380.   
  381.                 // Hide the element if the "hide" operation was done   
  382.                 if ( this.options.hide )   
  383.                     this.elem.style.display = "none";   
  384.   
  385.                 // Reset the properties, if the item has been hidden or shown   
  386.                 if ( this.options.hide || this.options.show )   
  387.                     for ( var p in this.options.curAnim )   
  388.                         jQuery.attr(this.elem.style, p, this.options.orig[p]);   
  389.             }   
  390.   
  391.             if ( done )// 运行complete的回调函数   
  392.                 this.options.complete.call( this.elem );   
  393.   
  394.             return false;   
  395.         } else {   
  396.             var n = t - this.startTime;   
  397.             this.state = n / this.options.duration;   
  398.   
  399.             // Perform the easing function, defaults to swing   
  400.             this.pos = jQuery.easing[this.options.easing || (jQuery.easing.swing ? "swing" : "linear")](this.state, n, 01this.options.duration);   
  401.             this.now = this.start + ((this.end - this.start) * this.pos);   
  402.   
  403.             // Perform the next step of the animation   
  404.             this.update();   
  405.         }   
  406.   
  407.         return true;   
  408.     }   
  409.   
  410. };   
  411.   
  412. jQuery.extend( jQuery.fx, {   
  413.     // 动画的速度   
  414.     speeds:{   
  415.         slow: 600,   
  416.         fast: 200,   
  417.         // Default speed   
  418.         _default: 400  
  419.     },   
  420.        
  421.     // 为元素设值   
  422.     step: {   
  423.         opacity: function(fx){// 为元素CSS设opacity为fx   
  424.             jQuery.attr(fx.elem.style, "opacity", fx.now);   
  425.         },   
  426.   
  427.         _default: function(fx){   
  428.             if( fx.prop in fx.elem ) // 对于元素   
  429.                 fx.elem[ fx.prop ] = fx.now;   
  430.             else if( fx.elem.style )// 对于style   
  431.                 fx.elem.style[ fx.prop ] = fx.now + fx.unit;   
  432.         }   
  433.     }   
  434. });  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值