本文参考了我佛山人的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://hmking.blog.51cto.com) 
  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.c***ules; 
  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