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

來源:互聯網
上載者:User

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來代替  可以直接的統一 ...

相關文章

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.