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