JQuery-1.9.1 source code analysis series (15) animation processing, jquery-1.9.1 source code

Source: Internet
Author: User

JQuery-1.9.1 source code analysis series (15) animation processing, jquery-1.9.1 source code

First, you must have basic knowledge about queues. See the previous chapter.

  

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 obtained by this algorithmN * 13It is not accurate, because the cpu is not just executed by a program, and the time slice is usually equalN * 13Large. 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: You must set the display feature value to inline-block for height/width-related animations in inline elements.

// 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 key 2: You must set height/width animation overflow to "hidden" and restore the animation after the animation 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 key 3: Special Handling of show/hide animations: show/hide animations call genFx to obtain the image

        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, the step value is 2 to skip the left/Right value // cssExpand = ["Top", "Right", "Bottom ", "Left"] includeWidth = includeWidth? 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 );

  

This chapter is first served here, followed by analysis.

 

If you think this article is good, click [recommendation] in the lower right corner ]!

  

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.