【JavaScript框架封裝】實現一個類似於JQuery的動畫框架的封裝

向善的燈發表於2018-07-19
版權宣告:本文為博主原創文章,未經博主允許不得轉載。更多學習資料請訪問我愛科技論壇:www.52tech.tech https://blog.csdn.net/m0_37981569/article/details/81123854
// 動畫框架
(function (xframe) {
    // 需要參與鏈式訪問的(必須使用prototype的方式來給物件擴充方法)
    xframe.extend({});

    // 不需要參與鏈式訪問的
    xframe.extend(xframe, {});


    // 實現動畫框架的封裝
    xframe.Animate = (function (xframe) {

        // 1. 定義需要的API介面(API內部用於放置屬性)
        var api = {
            timer: null,// 這是一個動畫迴圈控制程式碼
            queen: []  // 多個物件同時執行的一個陣列佇列
        };


        // 執行部門-------------------------------------------------
        /**
         * 在把需要的執行引數都準備好了之後(多個物件),就開始執行這個執行函式
         */
        api.run = function () {
            // 定義一個定時器,用於不斷地執行我自己定義的動畫函式資訊
            api.timer = setInterval(function () {
                // 由於所有的引數都已經準備好了,因此這裡只需要直接進行迴圈操作即可
                api.loop();
            }, 16);     // 這裡迴圈的週期設定的是16mm
        }
        /**
         * 執行動畫迴圈操作
         */
        api.loop = function () {
            // obj裡面儲存了obj = {id, now, pass, tween, duration, style}
            api.queen.forEach(function (obj) {
                // 遍歷佇列中的每一項引數,開始執行移動操作
                api.move(obj);
            });
        }
        /**
         * 實現物體的移動
         */
        api.move = function (obj) {
            // 1. 計算當前的時間
            obj.pass = +new Date();
            // 2. 獲取動畫時間程式(這裡的動畫樣式預設是一個彈簧的顯示樣式)
            var tween = api.getTween(obj.now, obj.pass, obj.duration, `easeOutBounce`);
            // 注意我們再每一次移動這個物體物件之前需要把這個物體物件的動畫時間程式更新一下,這樣到了後面的修改物件的屬性的時候這個引數的數值才會動態改變
            obj.tween = tween;

            //console.log(tween);

            // 3. 設定屬性資訊
            if (tween >= 1) {
                // 如果動畫時間程式結束了(百分比資訊)
                api.stop();
            } else {
                // 4. 通過設定物件的屬性資訊來移動每一個物件
                api.setManyProperty(obj);
            }
        }

        // 新增部門-------------------------------------------------
        /**
         * @param 獲取使用者輸入的引數,開始對引數進行解析,開始新增引數,然後實現動畫的開始執行
         */
        api.add = function () {
            var args = arguments,
                id = args[0],
                json = args[1],
                duration = args[2];

            // 獲取輸入的引數,然後開始使用介面卡解析資料
            try {
                // 1. 呼叫介面卡準備引數
                api.adapterMany(id, json, duration);

                // 2. 開始執行動畫
                api.run();
            } catch (e) {
                console.error(e.message);
            }
        }
        /**
         * 這是一個介面卡,用於解析一個物件的引數資訊(只能處理一個物件)
         * @param id
         * @param json
         * @param duration
         */
        api.adapterOne = function (id, json, duration) {
            var obj = {}                    // 這裡的OBj就是一個字面量格式, 用於儲存需要的引數資訊
            obj.id = id                     // ID編號
            obj.now = +new Date()           // 開始時間
            obj.pass = 0                    // 當前時間
            obj.tween = 0                   // 動畫時間程式
            obj.duration = duration         // 動畫的持續時間
            obj.styles = []                 // 用於存放所有的樣式資訊

            // 根據使用者輸入的引數資訊選擇不同的動畫速度
            if ($.isString(duration)) {
                switch (duration) {
                    case `slow`:
                    case `慢`:
                        duration = 8000;
                        break;
                    case `normal`:
                    case `普通`:
                        duration = 4000;
                        break;
                    case `fast`:
                    case `快`:
                        duration = 1000;
                        break;
                }
            }

            // 設定樣式資訊
            obj.styles = api.getStyles(id, json);
            return obj;
        }
        /**
         * 這個介面卡針對的是處理多個物件的動畫資訊
         * @param id
         * @param json
         * @param data
         */
        api.adapterMany = function (id, json, data) {
            // 處理多個物件的引數資訊(同樣的引數,但是需要處理不同的資訊,針對的是多個物件的引數)
            var obj = this.adapterOne(id, json, data);
            // 開始向我已有的佇列中新增資料資訊(此時queen佇列裡面就是存放了我所有的資料資訊)
            api.queen.push(obj);
        }
        /**
         * 獲取樣式資訊
         * @param id
         * @param json
         */
        api.getStyles = function (id, json) {
            // animate(`#sun`, {left: 200, top : 500}, 7000);
            // 把使用者傳遞過來的引數資訊轉換我需要的格式
            var styles = [];
            // 開始解析json資料資訊
            for (var item in json) {
                var style = {};
                // 這裡的item就是下面的:left, top
                style.name = item;
                // 獲取物體開始的位置
                style.start = parseFloat($(id).css(item).toString());
                // 計算物體的偏移量(移動的距離)
                style.length = parseFloat(json[item]) - style.start;

                styles.push(style);
            }
            return styles;
        }
        /**
         * 用於獲取一個動畫時間程式
         * @param now 開始時間
         * @param pass 當前時間
         * @param all 持續時間
         * @param ease 動畫效果
         */
        api.getTween = function (now, pass, all, ease) {
            // 1.定義常見的動畫效果
            var eases = {
                //線性勻速
                linear: function (t, b, c, d) {
                    return (c - b) * (t / d);
                },
                //彈性運動
                easeOutBounce: function (t, b, c, d) {
                    if ((t /= d) < (1 / 2.75)) {
                        return c * (7.5625 * t * t) + b;
                    } else if (t < (2 / 2.75)) {
                        return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
                    } else if (t < (2.5 / 2.75)) {
                        return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
                    } else {
                        return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
                    }
                },
                //其他
                swing: function (t, b, c, d) {
                    return this.easeOutQuad(t, b, c, d);
                },
                easeInQuad: function (t, b, c, d) {
                    return c * (t /= d) * t + b;
                },
                easeOutQuad: function (t, b, c, d) {
                    return -c * (t /= d) * (t - 2) + b;
                },
                easeInOutQuad: function (t, b, c, d) {
                    if ((t /= d / 2) < 1) return c / 2 * t * t + b;
                    return -c / 2 * ((--t) * (t - 2) - 1) + b;
                },
                easeInCubic: function (t, b, c, d) {
                    return c * (t /= d) * t * t + b;
                },
                easeOutCubic: function (t, b, c, d) {
                    return c * ((t = t / d - 1) * t * t + 1) + b;
                },
                easeInOutCubic: function (t, b, c, d) {
                    if ((t /= d / 2) < 1) return c / 2 * t * t * t + b;
                    return c / 2 * ((t -= 2) * t * t + 2) + b;
                },
                easeInQuart: function (t, b, c, d) {
                    return c * (t /= d) * t * t * t + b;
                },
                easeOutQuart: function (t, b, c, d) {
                    return -c * ((t = t / d - 1) * t * t * t - 1) + b;
                },
                easeInOutQuart: function (t, b, c, d) {
                    if ((t /= d / 2) < 1) return c / 2 * t * t * t * t + b;
                    return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
                },
                easeInQuint: function (t, b, c, d) {
                    return c * (t /= d) * t * t * t * t + b;
                },
                easeOutQuint: function (t, b, c, d) {
                    return c * ((t = t / d - 1) * t * t * t * t + 1) + b;
                },
                easeInOutQuint: function (t, b, c, d) {
                    if ((t /= d / 2) < 1) return c / 2 * t * t * t * t * t + b;
                    return c / 2 * ((t -= 2) * t * t * t * t + 2) + b;
                },
                easeInSine: function (t, b, c, d) {
                    return -c * Math.cos(t / d * (Math.PI / 2)) + c + b;
                },
                easeOutSine: function (t, b, c, d) {
                    return c * Math.sin(t / d * (Math.PI / 2)) + b;
                },
                easeInOutSine: function (t, b, c, d) {
                    return -c / 2 * (Math.cos(Math.PI * t / d) - 1) + b;
                },
                easeInExpo: function (t, b, c, d) {
                    return (t == 0) ? b : c * Math.pow(2, 10 * (t / d - 1)) + b;
                },
                easeOutExpo: function (t, b, c, d) {
                    return (t == d) ? b + c : c * (-Math.pow(2, -10 * t / d) + 1) + b;
                },
                easeInOutExpo: function (t, b, c, d) {
                    if (t == 0) return b;
                    if (t == d) return b + c;
                    if ((t /= d / 2) < 1) return c / 2 * Math.pow(2, 10 * (t - 1)) + b;
                    return c / 2 * (-Math.pow(2, -10 * --t) + 2) + b;
                },
                easeInCirc: function (t, b, c, d) {
                    return -c * (Math.sqrt(1 - (t /= d) * t) - 1) + b;
                },
                easeOutCirc: function (t, b, c, d) {
                    return c * Math.sqrt(1 - (t = t / d - 1) * t) + b;
                },
                easeInOutCirc: function (t, b, c, d) {
                    if ((t /= d / 2) < 1) return -c / 2 * (Math.sqrt(1 - t * t) - 1) + b;
                    return c / 2 * (Math.sqrt(1 - (t -= 2) * t) + 1) + b;
                },
                easeInElastic: function (t, b, c, d) {
                    var s = 1.70158;
                    var p = 0;
                    var a = c;
                    if (t == 0) return b;
                    if ((t /= d) == 1) return b + c;
                    if (!p) p = d * .3;
                    if (a < Math.abs(c)) {
                        a = c;
                        var s = p / 4;
                    }
                    else var s = p / (2 * Math.PI) * Math.asin(c / a);
                    return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
                },
                easeOutElastic: function (t, b, c, d) {
                    var s = 1.70158;
                    var p = 0;
                    var a = c;
                    if (t == 0) return b;
                    if ((t /= d) == 1) return b + c;
                    if (!p) p = d * .3;
                    if (a < Math.abs(c)) {
                        a = c;
                        var s = p / 4;
                    }
                    else var s = p / (2 * Math.PI) * Math.asin(c / a);
                    return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
                },
                easeInOutElastic: function (t, b, c, d) {
                    var s = 1.70158;
                    var p = 0;
                    var a = c;
                    if (t == 0) return b;
                    if ((t /= d / 2) == 2) return b + c;
                    if (!p) p = d * (.3 * 1.5);
                    if (a < Math.abs(c)) {
                        a = c;
                        var s = p / 4;
                    }
                    else var s = p / (2 * Math.PI) * Math.asin(c / a);
                    if (t < 1) return -.5 * (a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
                    return a * Math.pow(2, -10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
                },
                easeInBack: function (t, b, c, d, s) {
                    if (s == undefined) s = 1.70158;
                    return c * (t /= d) * t * ((s + 1) * t - s) + b;
                },
                easeOutBack: function (t, b, c, d, s) {
                    if (s == undefined) s = 1.70158;
                    return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
                },
                easeInOutBack: function (t, b, c, d, s) {
                    if (s == undefined) s = 1.70158;
                    if ((t /= d / 2) < 1) return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
                    return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
                },
                easeInBounce: function (t, b, c, d) {
                    return c - this.easeOutBounce(d - t, 0, c, d) + b;
                },
                easeInOutBounce: function (t, b, c, d) {
                    if (t < d / 2) return this.easeInBounce(t * 2, 0, c, d) * .5 + b;
                    return this.easeOutBounce(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
                }
            };
            // 2. 計算每一次動畫迴圈的小號時長
            var yongshi = pass - now;

            // 3. 獲取相應的動畫效果
            return eases[ease](yongshi, 0, 1, all);
        }

        /**
         * 通過設定一個物件的屬性資訊來實現物體的運動效果(如果只有一個屬性資訊的話)
         * @param obj
         */
        api.setOneProperty = function (obj) {
            // 用於設定一個物件的屬性資訊(obj.id, obj.json)
            // 【注意點】:這裡是動畫實現的一個核心要點,通過修改物件的屬性資訊來移動物體
            if (obj.name === `opacity`) {
                $(obj.id).css(obj.name, (obj.start + obj.length * obj.tween));
            } else {
                // 對於設定物件的其他屬性資訊都是需要新增一個px,畫素值資訊
                $(obj.id).css(obj.name, (obj.start + obj.length * obj.tween) + `px`);
            }
        }
        /**
         * 用於設定一個物件的鎖哥屬性資訊 obj.json = {width : `200px`, height : `500px`, `opacity` : `0.1`}
         */
        api.setManyProperty = function (obj) {
            // 由於obj.styles裡面是一個陣列
            obj.styles.forEach(function (style) {
                // 遍歷當前物件的所有樣式屬性資訊
                obj.name = style.name;
                obj.start = style.start;
                obj.length = style.length;
                api.setOneProperty(obj);
                console.log(obj.tween);
            });

            // 由於styles裡面只儲存了style.name, style.start, style.length三個屬性資訊, 因此需要處理一下

        }
        /**
         * 結束動畫的執行
         */
        api.stop = function () {
            clearInterval(api.timer);
        }

        // 後勤部門----------------------------------------------------
        api.destory = function () {

        }


        // 使用者只需要把需要的引數新增進來們就可以執行一個動畫
        // 使用者只需要傳進來三個引數,id, json, duration就可以實現一個動畫
        xframe.animate = api.add;

    })(xframe);
})(xframe);

 


相關文章