[Hỏi đáp] Code youtube loading bar

  Bài viết hay nhất1
Mình có đoạn code làm hiệu ứng loading giống trang youtube như thế này:
Code:
/*!
 * jQuery Transit - CSS3 transitions and transformations
 * (c) 2011-2012 Rico Sta. Cruz <rico@ricostacruz.com>
 * MIT Licensed.
 *
 * http://ricostacruz.com/jquery.transit
 * http://github.com/rstacruz/jquery.transit
 */

(function($) {
    $.transit = {
        version: "0.9.9",

        // Map of $.css() keys to values for 'transitionProperty'.
        // See https://developer.mozilla.org/en/CSS/CSS_transitions#Properties_that_can_be_animated
        propertyMap: {
            marginLeft    : 'margin',
            marginRight  : 'margin',
            marginBottom  : 'margin',
            marginTop    : 'margin',
            paddingLeft  : 'padding',
            paddingRight  : 'padding',
            paddingBottom : 'padding',
            paddingTop    : 'padding'
        },

        // Will simply transition "instantly" if false
        enabled: true,

        // Set this to false if you don't want to use the transition end property.
        useTransitionEnd: false
    };

    var div = document.createElement('div');
    var support = {};

    // Helper function to get the proper vendor property name.
    // (`transition` => `WebkitTransition`)
    function getVendorPropertyName(prop) {
        // Handle unprefixed versions (FF16+, for example)
        if (prop in div.style) return prop;

        var prefixes = ['Moz', 'Webkit', 'O', 'ms'];
        var prop_ = prop.charAt(0).toUpperCase() + prop.substr(1);

        if (prop in div.style) { return prop; }

        for (var i=0; i<prefixes.length; ++i) {
            var vendorProp = prefixes[i] + prop_;
            if (vendorProp in div.style) { return vendorProp; }
        }
    }

    // Helper function to check if transform3D is supported.
    // Should return true for Webkits and Firefox 10+.
    function checkTransform3dSupport() {
        div.style[support.transform] = '';
        div.style[support.transform] = 'rotateY(90deg)';
        return div.style[support.transform] !== '';
    }

    var isChrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1;

    // Check for the browser's transitions support.
    support.transition      = getVendorPropertyName('transition');
    support.transitionDelay = getVendorPropertyName('transitionDelay');
    support.transform      = getVendorPropertyName('transform');
    support.transformOrigin = getVendorPropertyName('transformOrigin');
    support.transform3d    = checkTransform3dSupport();

    var eventNames = {
        'transition':      'transitionEnd',
        'MozTransition':    'transitionend',
        'OTransition':      'oTransitionEnd',
        'WebkitTransition': 'webkitTransitionEnd',
        'msTransition':    'MSTransitionEnd'
    };

    // Detect the 'transitionend' event needed.
    var transitionEnd = support.transitionEnd = eventNames[support.transition] || null;

    // Populate jQuery's `$.support` with the vendor prefixes we know.
    // As per [jQuery's cssHooks documentation](http://api.jquery.com/jQuery.cssHooks/),
    // we set $.support.transition to a string of the actual property name used.
    for (var key in support) {
        if (support.hasOwnProperty(key) && typeof $.support[key] === 'undefined') {
            $.support[key] = support[key];
        }
    }

    // Avoid memory leak in IE.
    div = null;

    // ## $.cssEase
    // List of easing aliases that you can use with `$.fn.transition`.
    $.cssEase = {
        '_default':      'ease',
        'in':            'ease-in',
        'out':            'ease-out',
        'in-out':        'ease-in-out',
        'snap':          'cubic-bezier(0,1,.5,1)',
        // Penner equations
        'easeOutCubic':  'cubic-bezier(.215,.61,.355,1)',
        'easeInOutCubic': 'cubic-bezier(.645,.045,.355,1)',
        'easeInCirc':    'cubic-bezier(.6,.04,.98,.335)',
        'easeOutCirc':    'cubic-bezier(.075,.82,.165,1)',
        'easeInOutCirc':  'cubic-bezier(.785,.135,.15,.86)',
        'easeInExpo':    'cubic-bezier(.95,.05,.795,.035)',
        'easeOutExpo':    'cubic-bezier(.19,1,.22,1)',
        'easeInOutExpo':  'cubic-bezier(1,0,0,1)',
        'easeInQuad':    'cubic-bezier(.55,.085,.68,.53)',
        'easeOutQuad':    'cubic-bezier(.25,.46,.45,.94)',
        'easeInOutQuad':  'cubic-bezier(.455,.03,.515,.955)',
        'easeInQuart':    'cubic-bezier(.895,.03,.685,.22)',
        'easeOutQuart':  'cubic-bezier(.165,.84,.44,1)',
        'easeInOutQuart': 'cubic-bezier(.77,0,.175,1)',
        'easeInQuint':    'cubic-bezier(.755,.05,.855,.06)',
        'easeOutQuint':  'cubic-bezier(.23,1,.32,1)',
        'easeInOutQuint': 'cubic-bezier(.86,0,.07,1)',
        'easeInSine':    'cubic-bezier(.47,0,.745,.715)',
        'easeOutSine':    'cubic-bezier(.39,.575,.565,1)',
        'easeInOutSine':  'cubic-bezier(.445,.05,.55,.95)',
        'easeInBack':    'cubic-bezier(.6,-.28,.735,.045)',
        'easeOutBack':    'cubic-bezier(.175, .885,.32,1.275)',
        'easeInOutBack':  'cubic-bezier(.68,-.55,.265,1.55)'
    };

    // ## 'transform' CSS hook
    // Allows you to use the `transform` property in CSS.
    //
    //    $("#hello").css({ transform: "rotate(90deg)" });
    //
    //    $("#hello").css('transform');
    //    //=> { rotate: '90deg' }
    //
    $.cssHooks['transit:transform'] = {
        // The getter returns a `Transform` object.
        get: function(elem) {
            return $(elem).data('transform') || new Transform();
        },

        // The setter accepts a `Transform` object or a string.
        set: function(elem, v) {
            var value = v;

            if (!(value instanceof Transform)) {
                value = new Transform(value);
            }

            // We've seen the 3D version of Scale() not work in Chrome when the
            // element being scaled extends outside of the viewport.  Thus, we're
            // forcing Chrome to not use the 3d transforms as well.  Not sure if
            // translate is affectede, but not risking it.  Detection code from
            // http://davidwalsh.name/detecting-google-chrome-javascript
            if (support.transform === 'WebkitTransform' && !isChrome) {
                elem.style[support.transform] = value.toString(true);
            } else {
                elem.style[support.transform] = value.toString();
            }

            $(elem).data('transform', value);
        }
    };

    // Add a CSS hook for `.css({ transform: '...' })`.
    // In jQuery 1.8+, this will intentionally override the default `transform`
    // CSS hook so it'll play well with Transit. (see issue #62)
    $.cssHooks.transform = {
        set: $.cssHooks['transit:transform'].set
    };

    // jQuery 1.8+ supports prefix-free transitions, so these polyfills will not
    // be necessary.
    if ($.fn.jquery < "1.8") {
        // ## 'transformOrigin' CSS hook
        // Allows the use for `transformOrigin` to define where scaling and rotation
        // is pivoted.
        //
        //    $("#hello").css({ transformOrigin: '0 0' });
        //
        $.cssHooks.transformOrigin = {
            get: function(elem) {
                return elem.style[support.transformOrigin];
            },
            set: function(elem, value) {
                elem.style[support.transformOrigin] = value;
            }
        };

        // ## 'transition' CSS hook
        // Allows you to use the `transition` property in CSS.
        //
        //    $("#hello").css({ transition: 'all 0 ease 0' });
        //
        $.cssHooks.transition = {
            get: function(elem) {
                return elem.style[support.transition];
            },
            set: function(elem, value) {
                elem.style[support.transition] = value;
            }
        };
    }

    // ## Other CSS hooks
    // Allows you to rotate, scale and translate.
    registerCssHook('scale');
    registerCssHook('translate');
    registerCssHook('rotate');
    registerCssHook('rotateX');
    registerCssHook('rotateY');
    registerCssHook('rotate3d');
    registerCssHook('perspective');
    registerCssHook('skewX');
    registerCssHook('skewY');
    registerCssHook('x', true);
    registerCssHook('y', true);

    // ## Transform class
    // This is the main class of a transformation property that powers
    // `$.fn.css({ transform: '...' })`.
    //
    // This is, in essence, a dictionary object with key/values as `-transform`
    // properties.
    //
    //    var t = new Transform("rotate(90) scale(4)");
    //
    //    t.rotate            //=> "90deg"
    //    t.scale              //=> "4,4"
    //
    // Setters are accounted for.
    //
    //    t.set('rotate', 4)
    //    t.rotate            //=> "4deg"
    //
    // Convert it to a CSS string using the `toString()` and `toString(true)` (for WebKit)
    // functions.
    //
    //    t.toString()        //=> "rotate(90deg) scale(4,4)"
    //    t.toString(true)    //=> "rotate(90deg) scale3d(4,4,0)" (WebKit version)
    //
    function Transform(str) {
        if (typeof str === 'string') { this.parse(str); }
        return this;
    }

    Transform.prototype = {
        // ### setFromString()
        // Sets a property from a string.
        //
        //    t.setFromString('scale', '2,4');
        //    // Same as set('scale', '2', '4');
        //
        setFromString: function(prop, val) {
            var args =
                (typeof val === 'string')  ? val.split(',') :
                    (val.constructor === Array) ? val :
                        [ val ];

            args.unshift(prop);

            Transform.prototype.set.apply(this, args);
        },

        // ### set()
        // Sets a property.
        //
        //    t.set('scale', 2, 4);
        //
        set: function(prop) {
            var args = Array.prototype.slice.apply(arguments, [1]);
            if (this.setter[prop]) {
                this.setter[prop].apply(this, args);
            } else {
                this[prop] = args.join(',');
            }
        },

        get: function(prop) {
            if (this.getter[prop]) {
                return this.getter[prop].apply(this);
            } else {
                return this[prop] || 0;
            }
        },

        setter: {
            // ### rotate
            //
            //    .css({ rotate: 30 })
            //    .css({ rotate: "30" })
            //    .css({ rotate: "30deg" })
            //    .css({ rotate: "30deg" })
            //
            rotate: function(theta) {
                this.rotate = unit(theta, 'deg');
            },

            rotateX: function(theta) {
                this.rotateX = unit(theta, 'deg');
            },

            rotateY: function(theta) {
                this.rotateY = unit(theta, 'deg');
            },

            // ### scale
            //
            //    .css({ scale: 9 })      //=> "scale(9,9)"
            //    .css({ scale: '3,2' })  //=> "scale(3,2)"
            //
            scale: function(x, y) {
                if (y === undefined) { y = x; }
                this.scale = x + "," + y;
            },

            // ### skewX + skewY
            skewX: function(x) {
                this.skewX = unit(x, 'deg');
            },

            skewY: function(y) {
                this.skewY = unit(y, 'deg');
            },

            // ### perspectvie
            perspective: function(dist) {
                this.perspective = unit(dist, 'px');
            },

            // ### x / y
            // Translations. Notice how this keeps the other value.
            //
            //    .css({ x: 4 })      //=> "translate(4px, 0)"
            //    .css({ y: 10 })      //=> "translate(4px, 10px)"
            //
            x: function(x) {
                this.set('translate', x, null);
            },

            y: function(y) {
                this.set('translate', null, y);
            },

            // ### translate
            // Notice how this keeps the other value.
            //
            //    .css({ translate: '2, 5' })    //=> "translate(2px, 5px)"
            //
            translate: function(x, y) {
                if (this._translateX === undefined) { this._translateX = 0; }
                if (this._translateY === undefined) { this._translateY = 0; }

                if (x !== null && x !== undefined) { this._translateX = unit(x, 'px'); }
                if (y !== null && y !== undefined) { this._translateY = unit(y, 'px'); }

                this.translate = this._translateX + "," + this._translateY;
            }
        },

        getter: {
            x: function() {
                return this._translateX || 0;
            },

            y: function() {
                return this._translateY || 0;
            },

            scale: function() {
                var s = (this.scale || "1,1").split(',');
                if (s[0]) { s[0] = parseFloat(s[0]); }
                if (s[1]) { s[1] = parseFloat(s[1]); }

                // "2.5,2.5" => 2.5
                // "2.5,1" => [2.5,1]
                return (s[0] === s[1]) ? s[0] : s;
            },

            rotate3d: function() {
                var s = (this.rotate3d || "0,0,0,0deg").split(',');
                for (var i=0; i<=3; ++i) {
                    if (s[i]) { s[i] = parseFloat(s[i]); }
                }
                if (s[3]) { s[3] = unit(s[3], 'deg'); }

                return s;
            }
        },

        // ### parse()
        // Parses from a string. Called on constructor.
        parse: function(str) {
            var self = this;
            str.replace(/([a-zA-Z0-9]+)\((.*?)\)/g, function(x, prop, val) {
                self.setFromString(prop, val);
            });
        },

        // ### toString()
        // Converts to a `transition` CSS property string. If `use3d` is given,
        // it converts to a `-webkit-transition` CSS property string instead.
        toString: function(use3d) {
            var re = [];

            for (var i in this) {
                if (this.hasOwnProperty(i)) {
                    // Don't use 3D transformations if the browser can't support it.
                    if ((!support.transform3d) && (
                        (i === 'rotateX') ||
                            (i === 'rotateY') ||
                            (i === 'perspective') ||
                            (i === 'transformOrigin'))) { continue; }

                    if (i[0] !== '_') {
                        if (use3d && (i === 'scale')) {
                            re.push(i + "3d(" + this[i] + ",1)");
                        } else if (use3d && (i === 'translate')) {
                            re.push(i + "3d(" + this[i] + ",0)");
                        } else {
                            re.push(i + "(" + this[i] + ")");
                        }
                    }
                }
            }

            return re.join(" ");
        }
    };

    function callOrQueue(self, queue, fn) {
        if (queue === true) {
            self.queue(fn);
        } else if (queue) {
            self.queue(queue, fn);
        } else {
            fn();
        }
    }

    // ### getProperties(dict)
    // Returns properties (for `transition-property`) for dictionary `props`. The
    // value of `props` is what you would expect in `$.css(...)`.
    function getProperties(props) {
        var re = [];

        $.each(props, function(key) {
            key = $.camelCase(key); // Convert "text-align" => "textAlign"
            key = $.transit.propertyMap[key] || $.cssProps[key] || key;
            key = uncamel(key); // Convert back to dasherized

            if ($.inArray(key, re) === -1) { re.push(key); }
        });

        return re;
    }

    // ### getTransition()
    // Returns the transition string to be used for the `transition` CSS property.
    //
    // Example:
    //
    //    getTransition({ opacity: 1, rotate: 30 }, 500, 'ease');
    //    //=> 'opacity 500ms ease, -webkit-transform 500ms ease'
    //
    function getTransition(properties, duration, easing, delay) {
        // Get the CSS properties needed.
        var props = getProperties(properties);

        // Account for aliases (`in` => `ease-in`).
        if ($.cssEase[easing]) { easing = $.cssEase[easing]; }

        // Build the duration/easing/delay attributes for it.
        var attribs = '' + toMS(duration) + ' ' + easing;
        if (parseInt(delay, 10) > 0) { attribs += ' ' + toMS(delay); }

        // For more properties, add them this way:
        // "margin 200ms ease, padding 200ms ease, ..."
        var transitions = [];
        $.each(props, function(i, name) {
            transitions.push(name + ' ' + attribs);
        });

        return transitions.join(', ');
    }

    // ## $.fn.transition
    // Works like $.fn.animate(), but uses CSS transitions.
    //
    //    $("...").transition({ opacity: 0.1, scale: 0.3 });
    //
    //    // Specific duration
    //    $("...").transition({ opacity: 0.1, scale: 0.3 }, 500);
    //
    //    // With duration and easing
    //    $("...").transition({ opacity: 0.1, scale: 0.3 }, 500, 'in');
    //
    //    // With callback
    //    $("...").transition({ opacity: 0.1, scale: 0.3 }, function() { ... });
    //
    //    // With everything
    //    $("...").transition({ opacity: 0.1, scale: 0.3 }, 500, 'in', function() { ... });
    //
    //    // Alternate syntax
    //    $("...").transition({
    //      opacity: 0.1,
    //      duration: 200,
    //      delay: 40,
    //      easing: 'in',
    //      complete: function() { /* ... */ }
    //      });
    //
    $.fn.transition = $.fn.transit = function(properties, duration, easing, callback) {
        var self  = this;
        var delay = 0;
        var queue = true;

        var theseProperties = jQuery.extend(true, {}, properties);

        // Account for `.transition(properties, callback)`.
        if (typeof duration === 'function') {
            callback = duration;
            duration = undefined;
        }

        // Account for `.transition(properties, options)`.
        if (typeof duration === 'object') {
            easing = duration.easing;
            delay = duration.delay || 0;
            queue = duration.queue || true;
            callback = duration.complete;
            duration = duration.duration;
        }

        // Account for `.transition(properties, duration, callback)`.
        if (typeof easing === 'function') {
            callback = easing;
            easing = undefined;
        }

        // Alternate syntax.
        if (typeof theseProperties.easing !== 'undefined') {
            easing = theseProperties.easing;
            delete theseProperties.easing;
        }

        if (typeof theseProperties.duration !== 'undefined') {
            duration = theseProperties.duration;
            delete theseProperties.duration;
        }

        if (typeof theseProperties.complete !== 'undefined') {
            callback = theseProperties.complete;
            delete theseProperties.complete;
        }

        if (typeof theseProperties.queue !== 'undefined') {
            queue = theseProperties.queue;
            delete theseProperties.queue;
        }

        if (typeof theseProperties.delay !== 'undefined') {
            delay = theseProperties.delay;
            delete theseProperties.delay;
        }

        // Set defaults. (`400` duration, `ease` easing)
        if (typeof duration === 'undefined') { duration = $.fx.speeds._default; }
        if (typeof easing === 'undefined')  { easing = $.cssEase._default; }

        duration = toMS(duration);

        // Build the `transition` property.
        var transitionValue = getTransition(theseProperties, duration, easing, delay);

        // Compute delay until callback.
        // If this becomes 0, don't bother setting the transition property.
        var work = $.transit.enabled && support.transition;
        var i = work ? (parseInt(duration, 10) + parseInt(delay, 10)) : 0;

        // If there's nothing to do...
        if (i === 0) {
            var fn = function(next) {
                self.css(theseProperties);
                if (callback) { callback.apply(self); }
                if (next) { next(); }
            };

            callOrQueue(self, queue, fn);
            return self;
        }

        // Save the old transitions of each element so we can restore it later.
        var oldTransitions = {};

        var run = function(nextCall) {
            var bound = false;

            // Prepare the callback.
            var cb = function() {
                if (bound) { self.unbind(transitionEnd, cb); }

                if (i > 0) {
                    self.each(function() {
                        this.style[support.transition] = (oldTransitions[this] || null);
                    });
                }

                if (typeof callback === 'function') { callback.apply(self); }
                if (typeof nextCall === 'function') { nextCall(); }
            };

            if ((i > 0) && (transitionEnd) && ($.transit.useTransitionEnd)) {
                // Use the 'transitionend' event if it's available.
                bound = true;
                self.bind(transitionEnd, cb);
            } else {
                // Fallback to timers if the 'transitionend' event isn't supported.
                window.setTimeout(cb, i);
            }

            // Apply transitions.
            self.each(function() {
                if (i > 0) {
                    this.style[support.transition] = transitionValue;
                }
                $(this).css(properties);
            });
        };

        // Defer running. This allows the browser to paint any pending CSS it hasn't
        // painted yet before doing the transitions.
        var deferredRun = function(next) {
            this.offsetWidth; // force a repaint
            run(next);
        };

        // Use jQuery's fx queue.
        callOrQueue(self, queue, deferredRun);

        // Chainability.
        return this;
    };

    function registerCssHook(prop, isPixels) {
        // For certain properties, the 'px' should not be implied.
        if (!isPixels) { $.cssNumber[prop] = true; }

        $.transit.propertyMap[prop] = support.transform;

        $.cssHooks[prop] = {
            get: function(elem) {
                var t = $(elem).css('transit:transform');
                return t.get(prop);
            },

            set: function(elem, value) {
                var t = $(elem).css('transit:transform');
                t.setFromString(prop, value);

                $(elem).css({ 'transit:transform': t });
            }
        };

    }

    // ### uncamel(str)
    // Converts a camelcase string to a dasherized string.
    // (`marginLeft` => `margin-left`)
    function uncamel(str) {
        return str.replace(/([A-Z])/g, function(letter) { return '-' + letter.toLowerCase(); });
    }

    // ### unit(number, unit)
    // Ensures that number `number` has a unit. If no unit is found, assume the
    // default is `unit`.
    //
    //    unit(2, 'px')          //=> "2px"
    //    unit("30deg", 'rad')  //=> "30deg"
    //
    function unit(i, units) {
        if ((typeof i === "string") && (!i.match(/^[\-0-9\.]+$/))) {
            return i;
        } else {
            return "" + i + units;
        }
    }

    // ### toMS(duration)
    // Converts given `duration` to a millisecond string.
    //
    // toMS('fast') => $.fx.speeds[i] => "200ms"
    // toMS('normal') //=> $.fx.speeds._default => "400ms"
    // toMS(10) //=> '10ms'
    // toMS('100ms') //=> '100ms'
    //
    function toMS(duration) {
        var i = duration;

        // Allow string durations like 'fast' and 'slow', without overriding numeric values.
        if (typeof i === 'string' && (!i.match(/^[\-0-9\.]+/))) { i = $.fx.speeds[i] || $.fx.speeds._default; }

        return unit(i, 'ms');
    }

    // Export some functions for testable-ness.
    $.transit.getTransitionValue = getTransition;
})(jQuery);
Code:
(function ( $ ) {
    var PLUGIN_IDENTIFIER = 'ytLoad';
    var settings;
    var ajaxError;
    var barProgress;


    function injectProgressBar() {
        var $progressBar = $('#'+settings.progressBarId);

        if ($progressBar.length == 0) {
            $('body').append('<div id="'+settings.progressBarId+'" class="'+settings.progressBarId+'"><dt></dt><dd></dd></div>');
            $progressBar = $('#'+settings.progressBarId);
        }

        return $progressBar;
    }

    function getProgress() {
        return barProgress;
    }

    function setProgress(progress, duration, finished) {
        var $progressBar = injectProgressBar();
        if(!duration) {
            duration = (progress - barProgress) * settings.durationSeed;
        }
        barProgress = progress;
        var width = (101 / 100) * progress;
        width = Math.round(width * 100) / 100;

        // TODO: Is this a jquery.transit bug? Research error cause further and fill out proper bug report.
        var doubleCompletePrevention = false;

        $progressBar.transit({
            width: width+'%',
            duration: duration,
            complete: function() {
                if(doubleCompletePrevention) {
                    if(width > 99) {
                        $progressBar.delay(settings.fadeDelay);
                        $progressBar.fadeOut({
                            duration: settings.fadeDuration,
                            complete: function() {
                                $progressBar.remove();
                            }
                        });
                        settings.onComplete();
                    }
                    if(finished) {
                        finished();
                    }
                } else {
                    doubleCompletePrevention = true;
                }
            }
        });
    }

    var methods = {
        init: function(options) {
            ajaxError = false;
            progress = 0;

            settings = $.extend({
                registerAjaxHandlers: true,
                startPercentage: 30,
                startDuration: 200,
                completeDuration: 50,
                fadeDelay: 200,
                fadeDuration: 200,
                progressBarId: PLUGIN_IDENTIFIER,
                durationSeed: 8,
                onStart: function() { },
                onComplete: function() { },
                onError: function() { }
            }, options);

            if(settings.registerAjaxHandlers) {
                $(document).on('ajaxStart.'+PLUGIN_IDENTIFIER, function() {
                    methods.start();
                });

                $(document).on('ajaxComplete.'+PLUGIN_IDENTIFIER, function() {
                    if($.active < 2) {
                        methods.complete();
                    }
                });

                $(document).on('ajaxError.'+PLUGIN_IDENTIFIER, function() {
                    methods.error();
                });
            }
        },

        progress: function(progress, duration, finished) {
            if(!progress) {
                return getProgress();
            } else {
                setProgress(progress, duration, finished);
            }
        },

        start: function() {
            var $progressBar = injectProgressBar();
            ajaxError = false;

            methods.progress(settings.startPercentage, settings.startDuration);
            settings.onStart();
        },

        complete: function() {
            var $progressBar = injectProgressBar();
            methods.progress(100, settings.completeDuration);
        },

        error: function() {
            var $progressBar = $('#'+settings.progressBarId);
            $progressBar.addClass('error');

            settings.onError();
        },

        destroy: function() {
            if(settings.registerAjaxHandlers) {
                $(document).off('ajaxStart.'+PLUGIN_IDENTIFIER);
                $(document).off('ajaxComplete.'+PLUGIN_IDENTIFIER);
                $(document).off('ajaxError.'+PLUGIN_IDENTIFIER);
            }

            var $progressBar = $('#'+settings.progressBarId);
            if ($progressBar.length != 0) {
                $progressBar.remove();
            }
        }
    };

    $.ytLoad = function(methodOrOptions) {
        if ( methods[methodOrOptions] ) {
            return methods[ methodOrOptions ].apply( this, Array.prototype.slice.call( arguments, 1 ));
        } else if ( typeof methodOrOptions === 'object' || ! methodOrOptions ) {
            return methods.init.apply( this, arguments );
        } else {
            $.error( 'Method ' +  method + ' does not exist on jQuery.'+PLUGIN_IDENTIFIER );
        }
    };
}( jQuery ));
Code:
.ytLoad {
    position: fixed;
    z-index: 999;
    top: 0;
    left: -6px;
    width: 0%;
    height: 2px;
    background: #C9312C;
    -moz-border-radius: 1px;
    -webkit-border-radius: 1px;
    border-radius: 1px;
}
.ytLoad.error {
    background: #C20A47;
}

.ytLoad dd, .ytLoad dt {
    position: absolute;
    top: 0;
    height: 2px;
    -moz-box-shadow: #C9312C 1px 0 6px 1px;
    -ms-box-shadow: #C9312C 1px 0 6px 1px;
    -webkit-box-shadow: #C9312C 1px 0 6px 1px;
    box-shadow: #C9312C 1px 0 6px 1px;
    -moz-border-radius: 100%;
    -webkit-border-radius: 100%;
    border-radius: 100%;
}

.ytLoad.error dd, .ytLoad.error dt {
    -moz-box-shadow: #C20A47 1px 0 6px 1px;
    -ms-box-shadow: #C20A47 1px 0 6px 1px;
    -webkit-box-shadow: #C20A47 1px 0 6px 1px;
    box-shadow: #C20A47 1px 0 6px 1px;
}

.ytLoad dt {
    opacity: .6;
    width: 180px;
    right: -80px;
    clip: rect(-6px,90px,14px,-6px);
}

.ytLoad dd {
    opacity: .6;
    width: 20px;
    right: 0;
    clip: rect(-6px,22px,14px,10px);
}
Kích hoạt:
Code:
        <script type="text/javascript">

            $(document).ready(function() {
                var examples = {
                    customDurations: function() {
                        $.ytLoad();
                    },

                    manual: function() {
                        $.ytLoad({
                            registerAjaxHandlers: false
                        });
                        $.ytLoad('start');
                        $.ytLoad('complete');
                        $.ytLoad('error');
                    },

                    customDurations: function() {
                        $.ytLoad({
                            startPercentage: 50,
                            startDuration: 2000,
                            completeDuration: 500,
                            fadeDelay: 500,
                            fadeDuration: 500
                        });
                    },

                    setProgress: function() {
                        $.ytLoad({
                            registerAjaxHandlers: false
                        });

                        $.ytLoad('progress', 50);
                        alert($.ytLoad('progress'));
                        $.ytLoad('progress', 100);
                    },

                    callbacks: function() {
                        $.ytLoad({
                            onStart: function() {
                                alert('Started!');
                            },
                            onComplete: function() {
                                alert('Complete!');
                            }
                        });
                    },

                    multipleRequests: function() {
                        $.ytLoad();

                        for(i=0; i < 2000; i++) {
                            $('#ajaxContent').load('ajax.html');
                        }
                    }
                };

                $('#loadButton').click(function(){
                    $('#ajaxContent').load('ajax.html');
                });

                $('#usageType').change(function() {
                    $.ytLoad('destroy');
                    examples[$(this).val()]();
                });

                examples.customDurations();
            });
        </script>
Code trên chỉ chạy khi load đến js.
Bây giờ mình muốn sau khi click thì bar sẽ chạy một đoạn, sau khi chuyển trang thì nó sẽ chạy nốt đoạn còn lại thì phải sửa như thế nào?
  Bài viết hay nhất2
Loadingbar của youtube nó thể hiện tiến trình tải, còn bạn chỉ cần cái hiệu ứng thì không cần dùng nhiều thế này đâu.
Ý của bạn mình cũng không rõ lắm, nếu đã chuyển trang thì tất cả hiệu ứng hiện tại đã mất đi rồi, chưa kể đến là không biết bạn dùng nó như thế nào thì khó mà trả lời được.

Cách đơn giản để có hiệu ứng tải trang http://github.hubspot.com/pace/docs/welcome/
  Bài viết hay nhất3
Zzbaivong wrote:Loadingbar của youtube nó thể hiện tiến trình tải, còn bạn chỉ cần cái hiệu ứng thì không cần dùng nhiều thế này đâu.
Ý của bạn mình cũng không rõ lắm, nếu đã chuyển trang thì tất cả hiệu ứng hiện tại đã mất đi rồi, chưa kể đến là không biết bạn dùng nó như thế nào thì khó mà trả lời được.

Cách đơn giản để có hiệu ứng tải trang http://github.hubspot.com/pace/docs/welcome/
Ví dụ ở trang youtube, sau khi click nó chưa kịp chuyển trang thì thanh loading bar đã hiện lên rồi. sau khi chuyển sang trang clip khác thì nó vẫn giữ nguyên mức đó và chạy tiếp cho đến hết thanh loading bar và biến mất. như vậy làm ta có cảm giác đồng bộ giữa trang cũ và trang mới tải. ý mình là như vậy :D
  Bài viết hay nhất4
Đó không phải là chuyển trang đâu, họ dùng ajax để tải nội dung kế tiếp và dùng api history để viết lại đường dẫn.
Bạn dùng code như bình thường, và plugin pace nó sẽ bắt sự kiện đó và tạo hiệu ứng cho bạn, trước mình cũng dùng, vài hôm là chán thôi. :D
  Bài viết hay nhất5
You cannot reply to topics in this forum