jquery css() 方法的分析 于bug .

bug 描述 当 element 的 css  font-size:100% 此类百分比值的时候 我们将得到的是个错误的值 

而这个值是什么呢? 也许大家猜到了。 是的 就是父容器的 clientWidth*这个百分比

 

之所以会这样的原因是 因为 他的代码如下:

if(elem.currentStyle){//

r=elem.currentStyle [ styleString];//取到相应css属性的最终渲染值

if ( !/^\d+(px)?$/i.test( ret ) && /^\d/.test( ret ) ) {
    var left = style.left, rsLeft = elem.runtimeStyle.left;

    elem.runtimeStyle.left = elem.currentStyle.left;
    style.left = ret || 0;
    ret = style.pixelLeft + "px";

    style.left = left;
    elem.runtimeStyle.left = rsLeft;
   }

return ret;

解释下上面的代码  这里判断 如果 取到的r 的内容是数字开头 且不是 px结尾的 就要做 转换了 比如 100% 20em 30pt ex in之类的

如何转换呢? 本来是有转换公式的  比如 n em==n*16 px  , n pt==Math.floor(n*3/4) px  等等  但是jquery的方法就巧妙的很. 因为一旦值是 百分比

那么 对于 padding left top bottom right line-height margin 等等 所有的 % 都是和当前元素的父元素的 clientWidth 乘法运算得出的值....

这个原因 请去w3c手册自行查看 .现在 我们只要 去取父元素的 clientWidth 乘就是了 但是缺点是我们要为可能出现的 各种单位 去做 switch 还要正则匹配 取出 单位 然后要对不同单位应用不同的换算公式。 麻烦无比...

那么  jquery的做法 就是 如上面的代码 他 暂时把 当前元素的style.left 给一个变量保存  然后把 r 的值 (不管他是 em %  pt 还是什么)赋给 style.left 那么

当前元素的left位置自然会发生变化 这个时候 再通过 element.pixelLeft  自动换算出这个值对应的 px值 . 这样我们就取到了 正确的 px值了  这样行为就和

defaultView 的结果是一致的 都自动转换成了px . 然后再把 原来的 style.left的值 覆盖回去 恢复元素的style.left位置.

 

其中要提的是 element.runtimeStyle 为什么这里也把他临时覆盖了呢? 可能是出于 保险。比如 其他代码中可能更改了此值 因为 runtimeStyle的优先级 要高越style... 所以为了pixelLeft取出正确的值 所以 也覆盖了element.runtimeStyle.

 

那么bug来了  ie 中 字体的 % 百分比 是相对默认字体大小的 . 而这里他却 去和父容器的 clientWidth 去换算了 显然得出的值是错误的。

所以 应该如此判断 :(下面的代码是伪代码 jquery里跑不了 但思路是可以用的)

            var b = false;
            if (/^\d+/.test(r = node.currentStyle[styleString = ns.String.camelize(styleString)])) {
                if (!(b = /^font/.test(styleString)) || (b && r.match(/\D+$/)[0] != '%')) {
                    var left = node.style.left, rsLeft = node.runtimeStyle.left;
                    node.runtimeStyle.left = node.currentStyle.left;
                    node.style.left = r || 0;
                    r = node.style.pixelLeft;
                    node.style.left = left;
                    node.runtimeStyle.left = rsLeft;
                    return parseInt(r);
                }
                else if (node != document.body) return Math.floor(parseInt(r) * (parseInt(getCurrentStyle(document.body, 'font-size')) || 16) / 100);
                else return Math.floor(parseInt(r) * 16 / 100); 

那么接着说一说其他小bug.

这个bug本质来说和jquery无关 。是ie本身的问题 也就是 currentStyle的另外的问题

当 styleString为 float的时候  用currentStyle.cssFloat 这个大家都知道。

但问题是  ie 中 当前节点为 absolute 或relative  fixed的时候  很显然float是会失去作用的 那么其他浏览器 会最终返回none 无论你float里是不是 left 或right 他都返回none 因为浏览器最终渲染 是none 所以很明显ie这里 返回 left或right是不对的.那么我们就判断下好了

f (styleString == 'float') return ns.String.isInList(node.currentStyle.position, ['absolute', 'relative','fixed']) ? 'none' : node.currentStyle.styleFloat;

 

当然 这里认真的话还要判断ie6 fixed无效 所以渲染是有效的 问题. 不过 既然ie6 fixed无效 一般来说会给 ie 用absolute css hack 来模拟fixed 所以 判断不判断 无所谓了.

 

 还有功能上的疑问。 我不明白为什么jquery 不把 非ie浏览器 defaultView取出 的颜色值 如 rgb(255,255,255) 转换成 #ffffff 再返回 这样做不是更方便外面使用么? 可能是 因为他的set方法允许 此类参数吧. 但是我还是觉得转换一下的好

if (r.indexOf('rgb(', 0) >= 0) {
                var color = r;
                r = '';
                color.replace(/\d{1,3}/g, function(m) {
                    m = parseInt(m).toString(16);
                    r += m.length == 2 ? m : m = 0 + m;
                });
                return '#' + r;
            } 

 

 暂时就这些  至于其他的 如 left top 等值 不同浏览器不同 定位 等情况返回值差异问题 我觉得就没必要修复或统一...1是很麻烦. 再就是 我们可以用 element.offset来代替  可以直接的统一 ...

posted @ 2009-11-29 12:29  Franky  阅读(3055)  评论(2编辑  收藏  举报