1. 程式人生 > >js運動-offsetWidth和offsetHeight引發的血案

js運動-offsetWidth和offsetHeight引發的血案

之前說的js運動不管是單物體運動,多物體運動,還是緩衝運動。在獲取元素自身寬,高的時候用的都是offsetWidth,offsetHeight,但是這會引發一些麻煩!!因為jsoffsetWidthoffsetHeight獲取的不僅僅是元素樣式中定義的widthheight還包括給元素設定的borderpadding的值

看看下面的測試例子:

<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>