[转帖]Mootools源码分析-29 -- Fx.CSS

原帖地址:http://space.flash8.net/space/?uid-18713-action-viewspace-itemid-405471

原作者:我佛山人

 

//跟CSS有关的动画的基类,这里的动画,主要是从一个开始值到结束值的变化效果
Fx.CSS = new Class({
    
//继承自Fx
    Extends: Fx,
    
//prepares the base from/to object
    //动画的开始和结束值的前期处理
    prepare: function(element, property, values)    {
        
//数组化,因为values可能传一个单值,也可能是一个数组
        values = $splat(values);
        
//取数组中的第二个值,作为动画的结束值
        var values1 = values[1];
        
//如果只传了一个值
        if (!$chk(values1))    {
            
//将传的这个值作为动画的结束值
            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
    parse: function(value)    {
        
/*
        使用lambad表达式,将value函数化之后再执行
        这样的好处是使传的值可以是function,也可以是固定值
        
*/
        value 
= $lambda(value)();
        
//数组化,如果是字符串类型,使用空格分隔成数组
        value = (typeof value == 'string'? value.split(' ') : $splat(value);
        
//对数组逐项处理
        return value.map(function(val)    {
            
//转为字符类型
            val = String(val);
            
var found = false;
            Fx.CSS.Parsers.each(
function(parser, key)    {
                
//第一项时这里为false继续执行下面,找到合适的解释器后found判断不再为false,避免重复解释
                if (found)    return;
                
//尝试使用解释器解释值
                var parsed = parser.parse(val);
                
//如果解释成功,记录解释后的值和使用的解释器(因为还要使用解释器的compute和serve方法)
                if ($chk(parsed)) 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.
    //覆盖父类Fx的同名方法,不同的算法实现不同的效果
    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});
        });
        
//为$type提供精准类型值
        computed.$family = {name: 'fx:css:value'};
        
return computed;
    },

    
//serves the value as settable
    serve: function(value, unit)    {
        
//如果值未经解释,需要先解释
        if ($type(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 = {};
        
//遍历当前页面的样式表
        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 || !selectorText.test('^' + selector + '$'))    return;
                
//样式值分析
                Element.Styles.each(function(value, style)    {
                    
//无值
                    if (!rule.style[style] || Element.ShortStyles[style])    return;
                    
//转为字符串
                    value = String(rule.style[style]);
                    
//颜色值处理
                    to[style] = (value.test(/^rgb/)) ? value.rgbToHex() : value;
                });
            });
        });
        
//缓存
        return Fx.CSS.Cache[selector] = to;
    }
});

Fx.CSS.Cache 
= {};

//CSS中几种值类型的解释器,每个解释器必须实现parse/compute/serve三个接口
Fx.CSS.Parsers = new Hash({
    
//对颜色的解释处理
    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: 
function(value)    {
            
//转为浮点数
            return parseFloat(value);
        },
        compute: 
function(from, to, delta)    {
            
//跟Fx中的算法一样
            return Fx.compute(from, to, delta);
        },
        serve: 
function(value, unit)    {
            
//加上单位,比如px,pt之类
            return (unit) ? value + unit : value;
        }
    },

    
//对字符类型的解释处理
    String: {
        
//解释器返回false,相当于parse : function(){return false;}
        parse: $lambda(false),
        
//compute方法执行时返回第2个参数
        compute: $arguments(1),
        
//serve方法执行时返回第1个参数
        serve: $arguments(0)
    }
});

 

posted @ 2009-11-24 16:28  webgis松鼠  阅读(151)  评论(0编辑  收藏  举报