This article mainly introduces the jQuery1.9.1 source code analysis series (15) animation processing related information, need friends can refer to the first need to http://www.jb51.net/article/75771.htm "> queue (queue) basic knowledge. See the previous chapter.
Related Tutorials: jQuery animation processing summary: http://www.jb51.net/article/42000.htm
JQuery 1.9.1 source code analysis series (15th) animation processing-easing animation core Tween: http://www.jb51.net/article/75821.htm
A. Detailed description of the animation entry jQuery. fn. animate function Execution Process
--------------------------------------------------------------------------------
Call jQuery. speed according to the parameters to obtain the animation-related parameters and obtain an object similar to the following. Then, the animation execution function doAnimation is generated.
Optall = {complete: fnction (){...}, // callback duration for animation execution completion: 400, // animation execution duration easing: "swing", // animation effect queue: "fx", // animation queue old: false/fnction (){...},} var empty = jQuery. isEmptyObject (prop), optall = jQuery. speed (speed, easing, callback), doAnimation = function () {// operate on the feature copy to ensure that each feature effect will not be lost var anim = Animation (this, jQuery. extend ({}, prop), optall); doAnimation. finish = function () {anim. stop (true) ;}; // empty animation or completion must immediately solve if (empty | jQuery. _ data (this, "finish") {anim. stop (true) ;}}; doAnimation. finish = doAnimation;
If no animation is being executed, execute the animation immediately. Otherwise, press the animation into the animation queue for execution.
// If no animation is executed, execute the animation immediately. Otherwise, press the animation into the animation queue and wait for return empty | optall. queue = false? This. each (doAnimation): this. queue (optall. queue, doAnimation );
We can see that the Animation is actually executed by the Animation (this, jQuery. extend ({}, prop), optall) function.
B. Detailed description of the jQuery internal function Animation
--------------------------------------------------------------------------------
Animation (elem, properties, options). properties is the css feature to be animated, and options is an Animation-related option {complete: function (){...}, Duration: 400, easing: undefined, old: false, queue: "fx "}.
First, initialize a delayed object, which is used to process the animation queue.
deferred = jQuery.Deferred().always( function() { // don't match elem in the :animated selector delete tick.elem;}),
Then, generate a tick function that will be executed at each time point (the event interval between two adjacent time points is 13 milliseconds by default). This tick function will be stored in jQuery. timers, and then run jQuery every time. fx. tick will be extracted and executed.
Tick = function () {if (stopped) {return false;} var currentTime = fxNow | createFxNow (), remaining = Math. max (0, animation. startTime + animation. duration-currentTime), // archaic crash bug won't allow us to use 1-(0.5 | 0) (#12497) temp = remaining/animation. duration | 0, percent = 1-temp, index = 0, length = animation. tweens. length; // execute the animation effect for (; index <length; index ++) {animation. tweens [index]. run (percent);} // generate the progress report deferred. categorywith (elem, [animation, percent, remaining]); if (percent <1 & length) {return remaining;} else {// After the animation is executed, execute all functions in the delayed Queue (including clearing animation-related data) deferred. resolveWith (elem, [animation]); return false ;}}
We can see how jQuery processes the animation progress:
remaining = Math.max( 0, animation.startTime + animation.duration - currentTime )temp = remaining / animation.duration || 0,percent = 1 - temp,
Progress percentage = 1-Percentage of remaining time.
We usually do this: assume that the animation is executed at Nth time in 13 milliseconds, and the total animation duration is T. So
Progress percentage = (n * 13)/T
In fact, the time n * 13 obtained by this algorithm is not accurate, because the cpu is not just executed by one program, and the time slice is usually larger than n * 13. It is also an inaccurate value, which causes the animation to feel slow and incoherent. JQuery ensures the accuracy of the animation execution results on the current event point. After all, events are the latest computing results.
Third, the animation is generated. The animation object consists of all the features (the object structure is shown in the source code). The animation. props stores the user-passed features (the final goal of the animation ).
animation = deferred.promise({ elem: elem, props: jQuery.extend( {}, properties ), opts: jQuery.extend( true, { specialEasing: {} }, options ), originalProperties: properties, originalOptions: options, startTime: fxNow || createFxNow(), duration: options.duration, tweens: [], createTween: function( prop, end ) { var tween = jQuery.Tween( elem, animation.opts, prop, end, animation.opts.specialEasing[ prop ] || animation.opts.easing ); animation.tweens.push( tween ); return tween; }, stop: function( gotoEnd ) { var index = 0, // if we are going to the end, we want to run all the tweens // otherwise we skip this part length = gotoEnd ? animation.tweens.length : 0; if ( stopped ) { return this; } stopped = true; for ( ; index < length ; index++ ) { animation.tweens[ index ].run( 1 ); } // resolve when we played the last frame // otherwise, reject if ( gotoEnd ) { deferred.resolveWith( elem, [ animation, gotoEnd ] ); } else { deferred.rejectWith( elem, [ animation, gotoEnd ] ); } return this; }})
Fourth, call propFilter to correct the css feature name so that it can be recognized by the browser. Note that borderWidth/padding/margin is not a css feature, but four (up, down, and down)
// After propFilter, animation. opts. specialEasing, the corresponding feature propFilter (props, animation. opts. specialEasing) is added );
Examples illustrate the results of propFilter correction.
Example 1: The corrected css feature {height: 200} is as follows:
props = { height: 200 }animation.opts.specialEasing = {height: undefined}
Example 2: The correction result of css feature {margin: 200} is:
props = { marginBottom: 200,marginLeft: 200,marginRight: 200,marginTop: 200 }animation.opts.specialEasing = { marginBottom: undefined,marginLeft: undefined,marginRight: undefined,marginTop: undefined }
Fifth, call defaultPrefilter for adaptation processing: for example, the animation of height/width requires that the display and overflow be specific values for the effect; for example, for show/hide animation, a large number of css feature values need to be animated, and createTweens is called in the function to generate a easing animation.
// animationPrefilters[0] = defaultPrefilterfor ( ; index < length ; index++ ) { result = animationPrefilters[ index ].call( animation, elem, props, animation.opts ); if ( result ) { return result; }}
Among them, the value-worthy function of animationPrefilters [index] Is defaultPrefilter, and the processing of the defaultPrefilter function is important.
DefaultPrefilter key 1: The height/width-related animation in the inline element needs to set the display feature value to inline-block.
// Height/width overflow passif (elem. nodeType = 1 & ("height" in props | "width" in props, because IE cannot change the overflow feature value, // when overflowX and overflowY have the same value opts. overflow = [style. overflow, style. overflowX, style. overflowY]; // The height/width-related animation in the inline element requires that the display feature value be set to inline-block if (jQuery.css (elem, "display ") === "inline" & jQuery.css (elem, "float") === "none "){ // Inline elements accept inline-block; // block-level elements must be embedded in the layout if (! JQuery. support. inlineBlockNeedsLayout | css_defaultDisplay (elem. nodeName) = "inline") {style. display = "inline-block";} else {style. zoom = 1 ;}}}
DefaultPrefilter Focus 2: For height/width animation overflow, you must set it to "hidden" and restore the animation after it is completed. This helps increase the rendering speed.
// For the height/width animation overflow, you must set it to "hidden". After the animation is completed, restore if (opts. overflow) {style. overflow = "hidden"; // Contract The package if (! JQuery. support. shrinkWrapBlocks) {anim. always (function () {style. overflow = opts. overflow [0]; style. overflowX = opts. overflow [1]; style. overflowY = opts. overflow [2] ;}) ;}}
DefaultPrefilter highlights 3: special processing of show/hide animations: show/hide animations call genFx to get the shape as shown in
props = { height: "hide" marginBottom: "hide" marginLeft: "hide" marginRight: "hide" marginTop: "hide" opacity: "hide" paddingBottom: "hide" paddingLeft: "hide" paddingRight: "hide" paddingTop: "hide" width: "hide" }
The feature to be animated is pushed into the handled list and corresponding features are deleted. A corresponding easing animation is generated later.
For (index in props) {value = props [index]; // rfxtypes =/^ (?: Toggle | show | hide) $ /. We can see that only the animation with show/hide will be processed by the if (rfxtypes.exe c (value) {delete props [index] In Rao Ru handled; toggle = toggle | value = "toggle "; // if the status of the current node is the same as that of the specified node, you do not need to perform the next state judgment directly if (value = (hidden? "Hide": "show") {continue;} handled. push (index) ;}/// enter the branch for processing the animation to be executed. The animation length = handled is generated for each feature animation. length; if (length) {dataShow = jQuery. _ data (elem, "fxshow") | jQuery. _ data (elem, "fxshow", {}); if ("hidden" in dataShow) {hidden = dataShow. hidden;} // toggle needs to save the state-enables. stop (). toggle () to "reverse" if (toggle) {dataShow. hidden =! Hidden;} if (hidden) {jQuery (elem ). show ();} else {anim. done (function () {jQuery (elem ). hide () ;}) ;}anim. done (function () {var prop; jQuery. _ removeData (elem, "fxshow"); for (prop in orig) {jQuery. style (elem, prop, orig [prop]) ;}}; for (index = 0; index <length; index ++) {prop = handled [index]; // generate the easing animation tween = anim. createTween (prop, hidden? DataShow [prop]: 0); orig [prop] = dataShow [prop] | jQuery. style (elem, prop); if (! (Prop in dataShow) {dataShow [prop] = tween. start; if (hidden) {tween. end = tween. start; tween. start = prop = "width" | prop = "height "? 1: 0 ;}}}}
Sixth, generate a easing animation. show/hide has processed the animation in the defaultPrefilter function (the source code above ).
createTweens( animation, props );
Let's take a look at what is actually done in createTweens. Let's take a look at the animation object before createTweens.
Then, let's take a look at how the tweens array of the animation object after createTweens becomes
Divide margin into four attributes (marginTop/Right/Bottom/Left), and each attribute has its own animation features.
7. Start the animation timing and regularly execute tick
// Start the animation timing jQuery. fx. timer (jQuery. extend (tick, {elem: elem, anim: animation, queue: animation. opts. queue }));
Finally, add the input animation end callback to the delay queue.
// Obtain the callback function from options and add it to the delayed queue. return animation. progress (animation. opts. progress ). done (animation. opts. done, animation. opts. complete ). fail (animation. opts. fail ). always (animation. opts. always );
The process of the Animation function ends here.
Expansion:
The genFx function mentioned above is used to obtain relevant animation features for toggle, hide, and show.
The final generated attrs = {height: "show", marginTop: "show", marginRight: "show", // when the includeWidth is false, there is no marginBottom: "show", marginLeft: "show", // when includeWidth is false, no opacity: "show", width: "show"} function genFx (type, includeWidth) {var which, attrs = {height: type}, I = 0; // If the width is included, the step value is 1 to complete all cssExpand values. // If the width is not included, step value is 2 skip Left/Right value // cssExpand = ["Top", "Right", "Bottom", "Left"] includeWidth = includ EWidth? 1: 0; for (; I <4; I + = 2-direction dewidth) {which = cssExpand [I]; attrs ["margin" + which] = attrs ["padding" + which] = type;} if (includeWidth) {attrs. opacity = attrs. width = type;} return attrs ;}
The Animation function is complex. Kids shoes can use examples to trace code. This is a good way to understand jQuery source code. Two examples are recommended:
First, there is an example of hide/show: $ ("# id"). hide (1000 );
Second, other examples: $ ("# id"). animate ({"marginLeft": 500}, 1000 );
All the content of the jQuery 1.9.1 source code analysis series (15th) animation processing will be introduced here. If you have any questions, please feel free to leave a message. Thank you .!