讀古今文學網 > 編寫高質量代碼:改善JavaScript程序的188個建議 > 建議130:從CSS樣式表中抽取元素尺寸 >

建議130:從CSS樣式表中抽取元素尺寸

每個元素的顯示屬性都存儲在CSS樣式表中,如果能夠從中讀取元素的width和height屬性,就可以精確地獲得它的大小。在JavaScript中訪問和設置元素的CSS屬性,可以通過元素的style屬性進行。style是一個集合對象,它內部包含很多CSS腳本屬性。例如,使用style屬性設置元素的顯示寬度,並讀取該寬度值:


var p=document.getElementsByTagName(\"p\")[0];

p.style.;

var w=p.style.width;//返回字符串\"100px\"


但是,在JavaScript中設置或讀取CSS屬性值時,都必須包含單位,並且傳遞或返回的值都是字符串,同時通過這種方式獲得的信息往往是不準確的,因為style屬性中並不包含元素的樣式屬性的默認值。例如,在樣式表或行內樣式中未顯式定義p元素的寬度,根據它的默認值(即auto值),實際寬度顯示為100%。此時,如果使用元素的style屬性讀取width值,則返回空字符串。


<p></p>

<script language=\"javascript\"type=\"text/javascript\">

var p=document.getElementsByTagName(\"p\")[0];

alert(p.style.width);//返回空字符串

</script>


由於不同瀏覽器之間不兼容,獲取元素最終樣式的屬性還需要針對不同的瀏覽器分別設計,開發者應該考慮IE與支持DOM標準的瀏覽器存在不同的處理方法。

首先,自定義一個擴展函數來兼容IE和DOM的實現方法。擴展函數的參數為當前元素(即e)和它的屬性名(即n),函數返回值為該元素的樣式的屬性值。注意,這裡的屬性名是遵循駝峰命名法定義的CSS腳本屬性名。代碼如下:


//獲取指定元素的樣式屬性值

//參數:e表示具體的元素,n表示要獲取元素的腳本樣式的屬性名,如\"width\"、\"borderColor\"

//返回值:返回該元素e的樣式屬性n的值

function getStyle(e,n){

if(e.style[n]){

return e.style[n];

}

else if(e.currentStyle){

return e.currentStyle[n];

}

else if(document.defaultView&&document.defaultView.getComputedStyle){

n=n.replace(/([A-Z])/g,\"-$1\");

n=n.toLowerCase;

var s=document.defaultView.getComputedStyle(e,null);

if(s)

return s.getPropertyValue(n);

}

else

return null;

}


DOM標準在讀取CSS屬性值時的規定比較特殊,它遵循CSS語法規則中的約定來命名屬性名,即在復合屬性名中使用連字符來連接多個單詞,而不是遵循駝峰命名法,利用首字母大寫的方式來區分不同的單詞。例如,屬性borderColor在傳遞給DOM時就需要轉換為border-color,否則就會錯判。因此,傳遞的參數名還需要進行轉換,不過利用正則表達式可以輕鬆實現。下面調用這個擴展函數來獲取指定元素的實際寬度:


<p></p>

<script language=\"javascript\"type=\"text/javascript\">

var p=document.getElementsByTagName(\"p\")[0];

var w=getStyle(p,\"width\");//調用擴展函數,返回字符串\"auto\"

</script>


如果為p元素顯式定義200像素的寬度:


<p></p>


則調用擴展函數getStryle後會返回字符串「200px」:


var w=getStyle(p,\"width\");//調用擴展函數,返回字符串\"200px\"


雖然,我們知道auto值等於父元素的寬度,但是這只有通過人工計算才能夠獲取。例如,下面的示例中嵌套的結構就比較複雜,中間包含多層元素,並且寬度取值都是百分比,只需簡單的口算過程就可以知道,最內層元素的寬度的實際值為25像素。


<p >

<p >

<p >

<p >

<p></p>

</p>

</p>

</p>

</p>


設計一個簡單的迭代計算,使用getStyle擴展函數抽取每層元素的寬度值,然後把百分比轉換為數值,之後相乘即可。例如:


var p1=document.getElementsByTagName(\"p\")[0];

var w1=parseInt(getStyle(p1,\"width\"));

var p2=document.getElementsByTagName(\"p\")[1];

var w2=parseInt(getStyle(p2,\"width\"))/100;

var p3=document.getElementsByTagName(\"p\")[2];

var w3=parseInt(getStyle(p3,\"width\"))/100;

var p4=document.getElementsByTagName(\"p\")[3];

var w4=parseInt(getStyle(p4,\"width\"))/100;

var w=w1*w2*w3*w4;//返回數值25


上面的方法雖然很直接,但是比較簡陋,缺乏靈活性。下面設計一個擴展函數fromStyle,該函數對getStyle擴展函數的功能進行補充。設計fromStyle函數的參數為要獲取尺寸的元素,以及利用getStyle函數所得到的值,然後返回這個元素的具體尺寸值(即為具體的數字)。代碼如下:


//把fromStyle函數返回值轉換為實際的值

//參數:e表示具體的元素,w表示元素的樣式屬性值,通過getStyle函數獲取,p表示當前元素百分比轉換為小數的值,以便在上級元素中計算當前元素的尺寸

//返回值:返回具體的數字值

function fromStyle(e,w,p){

var p=arguments[2];

if(!p)p=1;

if(/px/.test(w)&&parseInt(w))return parseInt(parseInt(w)*p);

else if(/%/.test(w)&&parseInt(w)){//如果元素寬度值為百分比值

var b=parseInt(w)/100;

if((p!=1)&&p)b*=p;

e=e.parentNode;

if(e.tagName==\"BODY\")throw new Error(\"整個文檔結構都沒有定義固定尺寸,沒法計算了,請使用其他方法獲取尺寸.\");

w=getStyle(e,\"width\");

return arguments.callee(e,w,b);

}

else if(/auto/.test(w)){

var b=1;

if((p!=1)&&p)b*=p;

e=e.parentNode;

if(e.tagName==\"BODY\")throw new Error(\"整個文檔結構都沒有定義固定尺寸,沒法計算了,請使用其他方法獲取尺寸.\");

w=getStyle(e,\"width\");

return arguments.callee(e,w,b);

}

else

throw new Error(\"元素或其父元素的尺寸定義了特殊的單位.\");

}


最後,針對上面的嵌套結構,調用該函數就可以直接計算出元素的實際值:


var p=document.getElementById(\"p\");

var w=getStyle(p,\"width\");

w=fromStyle(p,w);//返回數值25


要獲取元素的高度值,在getStyle函數中修改第二個參數值為字符串「height」即可。