本文参考了我佛山人的Mootools1.2的源码分析二十九 -- Fx.CSS
1 /*
2 ---
3
4 name: Fx.CSS
5
6 description: Contains the CSS animation logic. Used by Fx.Tween, Fx.Morph, Fx.Elements.
7
8 license: MIT-style license.
9
10 requires: [Fx, Element.Style]
11
12 provides: Fx.CSS
13
14 源码分析: 苦苦的苦瓜(http://www.cnblogs.com/hmking)
15
16 ...
17 */
18
19 /**
20 * @Fx.CSS: 跟CSS有关的动画的基类,这里的动画,主要是从一个开始值到结束值的变化效果
21 **/
22 Fx.CSS = new Class({
23
24 // 继承自Fx
25 Extends: Fx,
26
27 // prepares the base from/to object
28 /**
29 * @method: prepare
30 * @param element - (object) 特效作用的元素对象
31 * @param property - (string) CSS属性
32 * @param values - (mixed) 包含开始值和结束值的数组或一个单值(结束值)
33 * @returns: (object) - 包含from和to两个键值的对象字面量
34 * @description: 动画的开始和结束值的前期处理
35 * @notes: 此时from和to两个键的值为数组类型
36 **/
37 prepare: function (element, property, values) {
38 // 把变量values数组化,因为values可能传一个单值,也可能是一个数组
39 values = Array.from(values);
40 // 取特效的起始值和结束值,如果如果只传了一个值,则本值将作为结束值,CSS属性的当前值为特效起始值
41 if (values[1] == null) {
42 values[1] = values[0];
43 values[0] = element.getStyle(property);
44 }
45 // 将数组中的项使用parse方法解释
46 var parsed = values.map(this.parse);
47 // 返回from和to两个键值的对象字面量
48 return { from: parsed[0], to: parsed[1] };
49 },
50
51 //parses a value into an array
52 /**
53 * @method: parse
54 * @param value - (mixed) CSS属性值
55 * @returns: (array) - 数组项值为包含value和parser两个键值的对象字面量,存储解释过的CSS属性值和包含针对此属性值的解释器
56 * @description: 解析一个CSS属性值为一个数组
57 **/
58 parse: function (value) {
59 // 使用lambad表达式,将value函数化之后再执行,这样的好处是使传的值可以是function,也可以是固定值
60 value = Function.from(value)();
61 // 数组化,如果是字符串类型,使用空格分隔成数组
62 value = (typeof value == 'string') ? value.split(' ') : Array.from(value);
63 // 对数组逐项处理
64 return value.map(function (val) {
65 // 转为字符类型
66 val = String(val);
67 var found = false;
68 Object.each(Fx.CSS.Parsers, function (parser, key) {
69 // 第一项时这里为false继续执行下面,找到合适的解释器后found判断不再为false,避免重复解释
70 if (found) { return; }
71 // 尝试使用解释器解释值
72 var parsed = parser.parse(val);
73 // 如果解释成功,记录解释后的值和使用的解释器(因为还要使用解释器的compute和serve方法)
74 if (parsed || parsed === 0) {
75 found = {
76 value: parsed,
77 parser: parser
78 };
79 }
80 });
81 // 默认使用字符串值的解释器
82 found = found || {
83 value: val,
84 parser: Fx.CSS.Parsers.String
85 };
86 return found;
87 });
88 },
89
90 // computes by a from and to prepared objects, using their parsers.
91 /**
92 * @method: compute
93 * @param from - (array) 解释过的CSS属性的起始值的数组
94 * @param to - (array) 解释过的CSS属性的结束值的数组
95 * @param delta - (mixed) 特效变化所需要的比例因子
96 * @returns: (array) 包含计算过的特效当前CSS属性值信息的一个数组
97 * @description: 根据初始值,结束值和比例因子求目标值
98 **/
99 compute: function (from, to, delta) {
100 var computed = [];
101 // 取数项小的遍历
102 (Math.min(from.length, to.length)).times(function (i) {
103 // 返回计算过的值和使用的解释器
104 computed.push({
105 value: from[i].parser.compute(from[i].value, to[i].value, delta),
106 parser: from[i].parser
107 });
108 });
109 // 为typeOf提供精准类型值
110 computed.$family = Function.from('fx:css:value');
111 return computed;
112 },
113
114 // serves the value as settable
115 /**
116 * @method: serve
117 * @param value - (mixed) CSS属性目标值,此参数可以是一个解释过的CSS属性值数组,也可以为一个CSS属性值
118 * @param unit - (string 默认为 false) 计量单位(如: 'px', 'em', 或 '%').
119 * @returns: (array) 包含计算过的特效当前CSS属性值信息的一个数组
120 * @description: 对计算过的CSS属性值数组对象做最后的包装处理,使其可应用于Element.setStyle方法
121 **/
122 serve: function (value, unit) {
123 // 如果值未经解释,需要先解释(比如单独调用set方法)
124 if (typeOf(value) != 'fx:css:value') {
125 value = this.parse(value);
126 }
127 var returned = [];
128 value.each(function (bit) {
129 // 得到最终的使用值
130 returned = returned.concat(bit.parser.serve(bit.value, unit));
131 });
132 return returned;
133 },
134
135 // renders the change to an element
136 // 因为类本身是跟CSS有类,所以最终将计算出的数组通过setStyle反映到element的相应CSS属性上
137 render: function (element, property, value, unit) {
138 element.setStyle(property, this.serve(value, unit));
139 },
140
141 // searches inside the page css to find the values for a selector
142 // 从当前页面的样式中查找指定选择符的样式设置
143 search: function (selector) {
144 // 模拟缓存,先从临时对象中找相应键值,提高效率
145 if (Fx.CSS.Cache[selector]) { return Fx.CSS.Cache[selector]; }
146 var to = {},
147 selectorTest = new RegExp('^' + selector.escapeRegExp() + '$');
148 // 遍历当前页面的样式表
149 Array.each(document.styleSheets, function (sheet, j) {
150 var href = sheet.href;
151 // 忽略跨域的外链样式表
152 if (href && href.contains('://') && !href.contains(document.domain)) {
153 return;
154 }
155 // 样式规则集
156 var rules = sheet.rules || sheet.cssRules;
157 // 遍历每条规则
158 Array.each(rules, function (rule, i) {
159 if (!rule.style) { return; }
160 // 选择符(类型选择符的话会转为小写)
161 var selectorText = (rule.selectorText) ? rule.selectorText.replace(/^\w+/, function (m) {
162 return m.toLowerCase();
163 }) : null;
164 // 匹配指定的样式选择符
165 if (!selectorText || !selectorTest.test(selectorText)) { return; }
166 // 样式值分析
167 Object.each(Element.Styles, function (value, style) {
168 // 无值
169 if (!rule.style[style] || Element.ShortStyles[style]) { return; }
170 // 转为字符串
171 value = String(rule.style[style]);
172 // 颜色值处理
173 to[style] = ((/^rgb/).test(value)) ? value.rgbToHex() : value;
174 });
175 });
176 });
177 // 缓存
178 return Fx.CSS.Cache[selector] = to;
179 }
180
181 });
182
183 Fx.CSS.Cache = {};
184
185 // #region - 解释器 -
186
187 // CSS中几种值类型的解释器,每个解释器必须实现parse/compute/serve三个接口
188 Fx.CSS.Parsers = {
189
190 // 对颜色的解释处理
191 Color: {
192
193 parse: function (value) {
194 // 如果是十六进制的颜色表示,处理成RGB数组
195 if (value.match(/^#[0-9a-f]{3,6}$/i)) {
196 return value.hexToRgb(true);
197 }
198 // 如果是RGB的颜色显示,正则匹配出RGB数组,不匹配返回flase,以便引擎调用其它解释器解释
199 return ((value = value.match(/(\d+),\s*(\d+),\s*(\d+)/))) ? [value[1], value[2], value[3]] : false;
200 },
201
202 compute: function (from, to, delta) {
203 // 对R、G和B分别计算目标值
204 return from.map(function (value, i) {
205 // 可以看到仍然使用静态的compute方法
206 return Math.round(Fx.compute(from[i], to[i], delta));
207 });
208 },
209
210 serve: function (value) {
211 // 将R、G、B都转成数值型
212 return value.map(Number);
213 }
214
215 },
216
217 // 数值类型的解释处理
218 Number: {
219
220 // 转为浮点数
221 parse: parseFloat,
222
223 // 跟Fx中的算法一样
224 compute: Fx.compute,
225
226 serve: function (value, unit) {
227 // 加上单位,比如px,pt之类
228 return (unit) ? value + unit : value;
229 }
230
231 },
232
233 // 对字符类型的解释处理
234 String: {
235
236 // 解释器返回false,相当于parse : function(){return false;}
237 parse: Function.from(false),
238
239 // compute方法执行时返回第2个参数
240 compute: function (zero, one) {
241 return one;
242 },
243
244 // serve方法执行时返回第1个参数
245 serve: function (zero) {
246 return zero;
247 }
248
249 }
250
251 };
252
253 // #endregion