MooTools1.4源碼分析- Fx.CSS

 本文參考瞭我佛山人的Mootools1.2的源碼分析二十九 — Fx.CSS
 
/*

 
name: Fx.CSS
 
description: Contains the CSS animation logic. Used by Fx.Tween, Fx.Morph, Fx.Elements.
 
license: MIT-style license.
 
requires: [Fx, Element.Style]
 
provides: Fx.CSS
 
源碼分析: 苦苦的苦瓜(http://hmking.blog.51cto.com)
 

*/
 
/**
* @Fx.CSS: 跟CSS有關的動畫的基類,這裡的動畫,主要是從一個開始值到結束值的變化效果
**/
Fx.CSS = new Class({
 
    // 繼承自Fx
    Extends: Fx,
 
    // prepares the base from/to object
    /**
    * @method: prepare
    * @param element – (object) 特效作用的元素對象
    * @param property – (string) CSS屬性
    * @param values – (mixed) 包含開始值和結束值的數組或一個單值(結束值)
    * @returns: (object) – 包含from和to兩個鍵值的對象字面量
    * @description: 動畫的開始和結束值的前期處理
    * @notes: 此時from和to兩個鍵的值為數組類型
    **/
    prepare: function (element, property, values) {
        // 把變量values數組化,因為values可能傳一個單值,也可能是一個數組
        values = Array.from(values);
        // 取特效的起始值和結束值,如果如果隻傳瞭一個值,則本值將作為結束值,CSS屬性的當前值為特效起始值
        if (values[1] == null) {
            values[1] = values[0];
            values[0] = element.getStyle(property);
        }
        // 將數組中的項使用parse方法解釋
        var parsed = values.map(this.parse);
        // 返回from和to兩個鍵值的對象字面量
        return { from: parsed[0], to: parsed[1] };
    },
 
    //parses a value into an array
    /**
    * @method: parse
    * @param value – (mixed) CSS屬性值
    * @returns: (array) – 數組項值為包含value和parser兩個鍵值的對象字面量,存儲解釋過的CSS屬性值和包含針對此屬性值的解釋器
    * @description: 解析一個CSS屬性值為一個數組
    **/
    parse: function (value) {
        // 使用lambad表達式,將value函數化之後再執行,這樣的好處是使傳的值可以是function,也可以是固定值
        value = Function.from(value)();
        // 數組化,如果是字符串類型,使用空格分隔成數組
        value = (typeof value == 'string') ? value.split(' ') : Array.from(value);
        // 對數組逐項處理
        return value.map(function (val) {
            // 轉為字符類型
            val = String(val);
            var found = false;
            Object.each(Fx.CSS.Parsers, function (parser, key) {
                // 第一項時這裡為false繼續執行下面,找到合適的解釋器後found判斷不再為false,避免重復解釋
                if (found) { return; }
                // 嘗試使用解釋器解釋值
                var parsed = parser.parse(val);
                // 如果解釋成功,記錄解釋後的值和使用的解釋器(因為還要使用解釋器的compute和serve方法)
                if (parsed || parsed === 0) {
                    found = {
                        value: parsed,
                        parser: parser
                    };
                }
            });
            // 默認使用字符串值的解釋器
            found = found || {
                value: val,
                parser: Fx.CSS.Parsers.String
            };
            return found;
        });
    },
 
    // computes by a from and to prepared objects, using their parsers.
    /**
    * @method: compute
    * @param from – (array) 解釋過的CSS屬性的起始值的數組
    * @param to – (array) 解釋過的CSS屬性的結束值的數組
    * @param delta – (mixed) 特效變化所需要的比例因子
    * @returns: (array) 包含計算過的特效當前CSS屬性值信息的一個數組
    * @description: 根據初始值,結束值和比例因子求目標值
    **/
    compute: function (from, to, delta) {
        var computed = [];
        // 取數項小的遍歷
        (Math.min(from.length, to.length)).times(function (i) {
            // 返回計算過的值和使用的解釋器
            computed.push({
                value: from[i].parser.compute(from[i].value, to[i].value, delta),
                parser: from[i].parser
            });
        });
        // 為typeOf提供精準類型值
        computed.$family = Function.from('fx:css:value');
        return computed;
    },
 
    // serves the value as settable
    /**
    * @method: serve
    * @param value – (mixed) CSS屬性目標值,此參數可以是一個解釋過的CSS屬性值數組,也可以為一個CSS屬性值
    * @param unit – (string 默認為 false) 計量單位(如: 'px', 'em', 或 '%').
    * @returns: (array) 包含計算過的特效當前CSS屬性值信息的一個數組
    * @description: 對計算過的CSS屬性值數組對象做最後的包裝處理,使其可應用於Element.setStyle方法
    **/
    serve: function (value, unit) {
        // 如果值未經解釋,需要先解釋(比如單獨調用set方法)
        if (typeOf(value) != 'fx:css:value') {
            value = this.parse(value);
        }
        var returned = [];
        value.each(function (bit) {
            // 得到最終的使用值
            returned = returned.concat(bit.parser.serve(bit.value, unit));
        });
        return returned;
    },
 
    // renders the change to an element
    // 因為類本身是跟CSS有類,所以最終將計算出的數組通過setStyle反映到element的相應CSS屬性上
    render: function (element, property, value, unit) {
        element.setStyle(property, this.serve(value, unit));
    },
 
    // searches inside the page css to find the values for a selector
    // 從當前頁面的樣式中查找指定選擇符的樣式設置
    search: function (selector) {
        // 模擬緩存,先從臨時對象中找相應鍵值,提高效率
        if (Fx.CSS.Cache[selector]) { return Fx.CSS.Cache[selector]; }
        var to = {},
                selectorTest = new RegExp('^' + selector.escapeRegExp() + '$');
        // 遍歷當前頁面的樣式表
        Array.each(document.styleSheets, function (sheet, j) {
            var href = sheet.href;
            // 忽略跨域的外鏈樣式表
            if (href && href.contains('://') && !href.contains(document.domain)) {
                return;
            }
            // 樣式規則集
            var rules = sheet.rules || sheet.cssRules;
            // 遍歷每條規則
            Array.each(rules, function (rule, i) {
                if (!rule.style) { return; }
                // 選擇符(類型選擇符的話會轉為小寫)
                var selectorText = (rule.selectorText) ? rule.selectorText.replace(/^\w+/, function (m) {
                    return m.toLowerCase();
                }) : null;
                // 匹配指定的樣式選擇符
                if (!selectorText || !selectorTest.test(selectorText)) { return; }
                // 樣式值分析
                Object.each(Element.Styles, function (value, style) {
                    // 無值
                    if (!rule.style[style] || Element.ShortStyles[style]) { return; }
                    // 轉為字符串
                    value = String(rule.style[style]);
                    // 顏色值處理
                    to[style] = ((/^rgb/).test(value)) ? value.rgbToHex() : value;
                });
            });
        });
        // 緩存
        return Fx.CSS.Cache[selector] = to;
    }
 
});
 
Fx.CSS.Cache = {};
 
// #region – 解釋器 –
 
// CSS中幾種值類型的解釋器,每個解釋器必須實現parse/compute/serve三個接口
Fx.CSS.Parsers = {
 
    // 對顏色的解釋處理
    Color: {
 
        parse: function (value) {
            // 如果是十六進制的顏色表示,處理成RGB數組
            if (value.match(/^#[0-9a-f]{3,6}$/i)) {
                return value.hexToRgb(true);
            }
            // 如果是RGB的顏色顯示,正則匹配出RGB數組,不匹配返回flase,以便引擎調用其它解釋器解釋
            return ((value = value.match(/(\d+),\s*(\d+),\s*(\d+)/))) ? [value[1], value[2], value[3]] : false;
        },
 
        compute: function (from, to, delta) {
            // 對R、G和B分別計算目標值
            return from.map(function (value, i) {
                // 可以看到仍然使用靜態的compute方法
                return Math.round(Fx.compute(from[i], to[i], delta));
            });
        },
 
        serve: function (value) {
            // 將R、G、B都轉成數值型
            return value.map(Number);
        }
 
    },
 
    // 數值類型的解釋處理
    Number: {
 
        // 轉為浮點數
        parse: parseFloat,
 
        // 跟Fx中的算法一樣
        compute: Fx.compute,
 
        serve: function (value, unit) {
            // 加上單位,比如px,pt之類
            return (unit) ? value + unit : value;
        }
 
    },
 
    // 對字符類型的解釋處理
    String: {
 
        // 解釋器返回false,相當於parse : function(){return false;}
        parse: Function.from(false),
 
        // compute方法執行時返回第2個參數
        compute: function (zero, one) {
            return one;
        },
 
        // serve方法執行時返回第1個參數
        serve: function (zero) {
            return zero;
        }
 
    }
 
};
 
// #endregion
作者“苦苦的苦瓜”

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *