js運動-offsetWidth和offsetHeight引發的血案
之前說的js運動不管是單物體運動,多物體運動,還是緩衝運動。在獲取元素自身寬,高的時候用的都是offsetWidth,offsetHeight,但是這會引發一些麻煩!!因為在js中offsetWidth,offsetHeight獲取的不僅僅是元素樣式中定義的width,height還包括給元素設定的border和padding的值
看看下面的測試例子:
<style> #div1{ width:200px;height: 100px; background: green; /*border: 5px solid #c00; padding: 5px;*/ } </style>
<body>
<div id="div1" onclick="test();"></div>
<script>
function test() {
var oDiv = document.getElementById('div1');
alert("offsetWidth 獲取的值是:"+oDiv.offsetWidth);
alert("offsetWidth 獲取的值是:"+oDiv.offsetHeight);
}
</script>
</body>
不加border和padding的時候,彈出的值都是200和100,加了border和padding結果就成了220和120,所以offsetWidth = width + border + padding
明白了上面的問題,接下來看看offsetWidth/Height在會帶來哪些麻煩??
改一下上面的案例,當點選div的時候,讓div寬度逐漸變窄
<script>
function test() {
var oDiv = document.getElementById('div1');
setInterval(function () {
oDiv.style.width = oDiv.offsetWidth-1 + 'px';
},30);
}
</script>
如上圖所示:當不加boder和padding的時候,點選div發現很正常div逐漸變窄
當我們給div加了邊框或者padding的時候,神器的事情發生了,為了看的清楚給div了2px的黃色邊框,當我們點選div的時候div的寬度並沒有變窄,反而越變越寬???這是為什麼那??仔細分析
當我們點選div的時候oDiv.offsetWidth獲取的值是204,然後oDiv.style.width = 204-1即203
加上左右2px的border就成了205,所以30毫秒後,oDiv.offsetWidth取得205,然後減1變成204,再賦給oDiv.style.width,接著在加上左右2px的border就成了206,如此迴圈下去,導致div的寬就越變越大了。
那如何解決這個問題那??
我們只要獲取div自身的寬度width,而不要包括(border和padding的寬),這樣問題就解決了,那怎麼獲取div自身的寬度同時又不包括border和padding的寬那??不用offsetWidth來獲取。
在DOM標準的API裡有這樣一個方法getComputedStyle,通過這個方法可以可以獲取到當前物件樣式規則資訊,getComputedStyle(obj,null).width,就能獲取到物件自身的寬度(不包括border和padding),但是IE不支援此方法,IE需要用currentStyle,不同於全域性方法getComputedStyle,它是作為DOM元素屬性存在的,如:obj.currentStyle.width,在IE中就獲取到物件自身的寬度了.
在如:getComputedStyle(obj,null).paddingLeft和 obj.currentStyle.paddingLeft就能獲取到物件的左內邊距;
getComputedStyle(obj,null).borderWidth和 obj.currentStyle.borderWidtht就能獲取到物件上下左右邊框的寬度。
關於更加詳細可以獲取和操作哪些屬性參考:http://www.jb51.net/shouce/dhtml/objects/currentStyle.html
注意一點:如果要獲取當前物件的顏色資訊,currentStyle返回的是16進位制的'#ffffff',而getComputedStyle返回的是rgb(255,255,255)
<script>
function test() {
var oDiv = document.getElementById('div1');
alert("getComputedStyle獲取的寬度是:" + getComputedStyle(oDiv,false).width);
}
</script>
測試一下,儘管我們添加了2px的border,但是彈出的結果任然是200px
注意:getComputedStyle獲取的結果是字串,需要用 parseInt( )轉換一下;然後將之前程式中的offsetWidth換成getComputedStyle之後,在點選div就不再變寬了,而是正常的變窄了
<script>
function test() {
var oDiv = document.getElementById('div1');
setInterval(function () {
oDiv.style.width = parseInt(getComputedStyle(oDiv,false).width)-1 + 'px';
},30);
}
</script>
把之前多物體運動中通過offsetWidht獲取物體的寬度,改成getComputedStyle
為了方便,且瀏覽器相容,我們封裝一個函式getStyle
function getStyle(obj,attr){
/*if(obj.currentStyle){
return obj.currentStyle[attr];// ie
}else{
return getComputedStyle(obj,false)[attr];
}*/
return getComputedStyle?getComputedStyle(obj,false)[attr]: obj.currentStyle[attr];
}
完整程式碼:
<ul>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
樣式:
<style>
ul{list-style: none;}
ul li{
margin: 10px;
width: 200px;height: 50px;
border: 2px solid #c00;
background: lightblue;
}
</style>
<script>
window.onload = function(){
var liTags = document.getElementsByTagName('li');
for(var i=0;i<liTags.length;i++){
liTags[i].timer = null;// 給每個li都新增一個timer
liTags[i].onmouseover = function () {
startMove(this,400);
}
liTags[i].onmouseout = function () {
startMove(this,200);
}
}
}
function getStyle(obj,attr){
return getComputedStyle ? getComputedStyle(obj,false)[attr] : obj.currentStyle[attr];
}
function startMove(obj,iTarget) {
clearInterval(obj.timer);
obj.timer = setInterval(function () {
var objWidth = parseInt(getStyle(obj,'width'));//因為是通過[]呼叫屬性,所以width必須加單引號
// var iSpeed = (iTarget -obj.offsetWidth)/10;
// 因為objWidth存放的就是當前物件的寬,所以直接寫objWidth而不是obj.objWidth
var iSpeed = (iTarget -objWidth)/10;
iSpeed = iSpeed>0 ?Math.ceil(iSpeed):Math.floor(iSpeed);
if(objWidth == iTarget){
clearInterval(obj.timer);
}else{
obj.style.width = objWidth+iSpeed+'px';
}
},30);
}
</script>