[转帖]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)
}
});
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)
}
});