讀古今文學網 > 編寫高質量代碼:改善JavaScript程序的188個建議 > 建議131:慎重使用offsetWidth和offsetHeight >

建議131:慎重使用offsetWidth和offsetHeight

可以使用offsetWidth和offsetHeight屬性來獲取元素的尺寸,其中offsetWidth表示元素在頁面中所佔據的總寬度,offsetHeight表示元素在頁面中所佔據的總高度。例如:


<p >

<p >

<p >

<p >

<p></p>

</p>

</p>

</p>

</p>

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

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

var w=p.offsetWidth;//返回元素的總寬度

var h=p.offsetHeight;//返回元素的總高度

</script>


上面的示例在IE的「怪異」模式下和支持DOM模型的瀏覽器中解析結果差異很大,其中在IE「怪異」模式下解析返回寬度為13像素,高度為26像素,而在支持DOM模型的瀏覽器中返回高度和寬度都為18像素(但是FF返回19像素,因為小數取捨方法不同)。

IE「怪異」模式是一種非標準的解析方法,與標準模式相對應,主要是IE為了兼容大量傳統佈局的網頁而採用的。「怪異」模式在IE 6.0以下版本中存在,但在IE 6.0及其以上版本中,如果將頁面明確設置為「怪異」模式顯示,或者HTML文檔的DOCTYPE(文檔類型)沒有明確定義,也會按「怪異」模式進行解析。

根據示例中內行樣式定義的值,可以算出最內層元素的寬和高都為12.5像素,實際取值為12像素。但對於IE「怪異」解析模式來說,樣式屬性width和height的值就是元素的總寬度和總高度。由於IE是根據四捨五入法處理小數部分的,因此該元素的總高度和總寬度都是13像素。同時,由於IE模型定義每個元素都有一個默認行高,即使元素內不包含任何文本,因此實際高度就顯示為26像素。

而對於支持DOM模型的瀏覽器來說,它們認為元素樣式屬性中的寬度和高度僅是元素內部包含的內容區域的尺寸,而元素的總高度和總寬度應該加上補白和邊框,由於元素默認邊框值為3像素,因此最後計算的總高度和總寬度都是18像素。至於,Firefox返回值為19像素,是因為它在處理小數部分時,並沒有完全捨去,而是根據條件和環境的不同增加了1個像素值。

也許offsetWidth和offsetHeight屬性是獲取元素尺寸的最好的方法,但在實踐中會發現:當為元素定義隱藏屬性,即設置樣式屬性display的值為none時,元素的尺寸總為0,代碼如下:


<p></p>

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

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

var w=p.offsetWidth;//返回0

var h=p.offsetHeight;//返回0

</script>


這種情況還會發生在父級元素的display樣式屬性為none時,即使當前元素沒有設置隱藏顯示,根據繼承關係也會將其隱藏顯示,此時offsetWidth和offsetHeight屬性值都是0。總之,對於隱藏元素來說,不管它的實際高度和寬度是多少,最終讀取的offsetWidth和offsetHeight屬性值都是0。

要解決這個問題,還需要自定義函數專門彌補offsetWidth和offsetHeight屬性的缺陷。具體設計思路:先判斷元素的樣式屬性display的值是否為none,如果不是,則直接調用offsetWidth和offsetHeight屬性讀取元素的寬和高即可。如果元素的樣式屬性display的值為none,則可以暫時顯示元素,然後讀取它的尺寸,讀取完之後再把它恢復為隱藏樣式。為此,不妨先設計兩個小的功能函數,通過它們可以分別重設和恢復元素的樣式屬性值。代碼如下:


//重設元素的樣式屬性值

//參數:e表示重設樣式的元素,o表示要設置的值,它是一個對象,可以包含多個名-值對

//返回值:重設樣式的原屬性值,以對像形式返回

function setCSS(e,o){

var a={};

for(var i in o){

a[i]=e.style[i];

e.style[i]=o[i];

}

return a;

}

//恢復元素的樣式屬性值

//參數:e表示重設樣式的元素,o表示要恢復的值,它是一個對象,可以包含多個名-值對

//返回值:無

function resetCSS(e,o){

for(var i in o){

e.style[i]=o[i];

}

}


有了這兩個小的功能函數後,再自定義函數getW和getH,不管元素是否被隱藏顯示,這兩個函數能夠獲取元素的寬度和高度。具體實現代碼如下:


//獲取元素的存在寬度

//參數:e表示元素

//返回值:存在寬度

function getW(e){

if(getStyle(e,\"display\")!=\"none\")return e.offsetWidth||fromStyle(getStyle(e,\"width\"));

var r=setCSS(e,{

display:\"\",

position:\"absolute\",

visibility:\"hidden\"

});

var w=e.offsetWidth||fromStyle(getStyle(e,\"width\"));

resetCSS(e,r);

return w;//返回存在寬度

}

//獲取元素的存在高度

//參數:e表示元素

//返回值:存在高度

function getH(e){

if(getStyle(e,\"display\")!=\"none\")return e.offsetHeight||fromStyle(getStyle(e,\"height\"));

var r=setCSS(e,{

display:\"\",

position:\"absolute\",

visibility:\"hidden\"

});

var h=e.offsetHeight||fromStyle(getStyle(e,\"height\"));

resetCSS(e,r);

return h;

}


最後,調用getW和getH擴展函數來測試它的性能:


<p></p>

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

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

var w=p.offsetWidth;//返回0

var h=p.offsetHeight;//返回0

var w1=getW(p);//返回200

var h1=getH(p);//返回200

</script>