天天看點

js中的offsetLeft和style.left

(1)style.left是帶機關"px"的,而offsetLeft沒有機關,另外,style.left必須是内聯樣式,或者在JS中通過style.left指派,否則取得的将為空字元串(在内部樣式和外部樣式中指定left是無效的)

(2)如果沒有已經定位的父元素,那麼offsetLeft指向的是文檔(document)的左邊緣

<!DOCTYPE html>
<html >
<head>
    <meta charset="UTF-8">
    <title>OFFSET</title>
    <style>
        #div1{
            height: 500px;
            width:500px;
            border: 1px solid red;
        }
        #div2{
            width: 100px;
            height: 100px;
            background: blue;
            margin-left: 100px;
        }

    </style>
</head>
<body>
    <div id="div1">
        <div id="div2"></div>
    </div>
    <button onclick="handle()">click</button>
    <script>

        function handle(){
            var d2 = document.getElementById("div2");
            alert(d2.offsetLeft);  //109
            console.log(d2.style.left)  //列印空白
        }
    </script>
</body>
</html>
           
js中的offsetLeft和style.left

(3)父元素相對定位(代碼結構如上,就是父元素增加position:relative)子元素的offsetLeft是相對于父元素

#div1{
            height: 500px;
            width:500px;
            border: 1px solid red;
            position: relative;
        }
           
js中的offsetLeft和style.left

子元素增加了position:absolute和left:10px; offsetLeft依然是相對于父 

js中的offsetLeft和style.left

(4)擷取offsetLeft、offsetTop、offsetWidth、offsetHeight 

<!DOCTYPE html>
<html >
<head>
    <meta charset="UTF-8">
    <title>OFFSET</title>
    <style>
        #div1{
            height: 500px;
            width:500px;
            border: 1px solid red;
            position: relative;
        }
        #div2{
            width: 100px;
            height: 100px;
            background: blue;
            margin-left: 100px;
            position: absolute;
        }

    </style>
</head>
<body>
    <div id="div1">
        <div id="div2"></div>
    </div>
    <button onclick="handle()">click</button>
    <script>

        function handle(){
            var d2 = document.getElementById("div2");
            console.log(offset(d2)); 
            
        }

          function offset(elem){
            var obj={
                left:elem.offsetLeft,
                top:elem.offsetTop,
                width:elem.offsetWidth,
                height:elem.offsetHeight
            }
          
            return obj;
  }

 
    </script>
</body>
</html>
           
js中的offsetLeft和style.left

(5)offsetParent的作用 

<!DOCTYPE html>
<html >
<head>
    <meta charset="UTF-8">
    <title>OFFSET</title>
    <style>
        #div1{
            height: 500px;
            width:500px;
            border: 1px solid red;
            position: relative;
        }
        #div2{
            width: 100px;
            height: 100px;
            background: blue;
            margin-left: 100px;
            position: absolute;
        }

    </style>
</head>
<body>
    <div id="div1">
        <div id="div2"></div>
    </div>
    <button onclick="handle()">click</button>
    <script>

        function handle(){
            var d2 = document.getElementById("div2");
            console.log(offset(d2)); 

        }

        function offset(elem){
            var obj={
                left:elem.offsetLeft,
                top:elem.offsetTop,
                width:elem.offsetWidth,
                height:elem.offsetHeight
            }
           while(elem != document.body){
                elem = elem.offsetParent ; 
                console.log(elem);
                obj.left += elem.offsetLeft ;  //得到是元素距離視口的左邊距和上邊距(不包括border)
                obj.top += elem.offsetTop ;
            }
            return obj;

}

 
    </script>
</body>
</html>
           

解釋:

 偏移量(offset dimension)是javascript中的一個重要的概念。涉及到偏移量的主要是offsetLeft、offsetTop、offsetHeight、offsetWidth這四個屬性。當然,還有一個偏移參照——定位父級offsetParent。本文将詳細介紹該部分内容

js中的offsetLeft和style.left

定位父級

  在了解偏移大小之前,首先要了解offsetParent。人們并沒有把offsetParent翻譯為偏移父級,而是翻譯成定位父級,很大原因是offsetParent與定位有關

  定位父級offsetParent的定義是:與目前元素最近的經過定位(position不等于static)的父級元素,主要分為下列幾種情況 

  【1】元素自身有fixed定位,offsetParent的結果為null

  當元素自身有fixed固定定位時,我們知道固定定位的元素相對于視口進行定位,此時沒有定位父級,offsetParent的結果為null

  [注意]firefox浏覽器有相容性問題

<div id="test" style="position:fixed"></div>    
<script>
//firefox并沒有考慮固定定位的問題,傳回<body>,其他浏覽器都傳回null
console.log(test.offsetParent);
</script>
           

【2】元素自身無fixed定位,且父級元素都未經過定位,offsetParent的結果為<body>

<div id="test"></div>    
<script>
console.log(test.offsetParent);//<body>
</script>
           

【3】元素自身無fixed定位,且父級元素存在經過定位的元素,offsetParent的結果為離自身元素最近的經過定位的父級元素 

<div id="div0" style="position:absolute;">
    <div id="div1" style="position:absolute;">
        <div id='test'></div>    
    </div>    
</div>
<script>
console.log(test.offsetParent);    //<div id="div1">
</script>
           

 【4】<body>元素的parentNode是null

console.log(document.body.offsetParent);//null
           

IE7-浏覽器Bug

  對于定位父級offsetParent來說,IE7-浏覽器存在以下bug

  【bug1】當元素本身經過絕對定位或相對定位,且父級元素無經過定位的元素時,IE7-浏覽器下,offsetParent是<html>

<div id="test" style="position:absolute;"></div>    
<script>
//IE7-浏覽器傳回<html>,其他浏覽器傳回<body>
console.log(test.offsetParent);
</script>

<div id="test" style="position:relative;"></div>    
<script>
//IE7-浏覽器傳回<html>,其他浏覽器傳回<body>
console.log(test.offsetParent);
</script>

<div id="test" style="position:fixed;"></div>    
<script>
//firefox并沒有考慮固定定位的問題,傳回<body>,其他浏覽器都傳回null
console.log(test.offsetParent);
</script>
           

【bug2】如果父級元素存在觸發haslayout的元素或經過定位的元素,且offsetParent的結果為離自身元素最近的經過定位或觸發haslayout的父級元素

  [注意]關于haslayout的詳細資訊移步至此

<div id="div0" style="display:inline-block;">
    <div id='test'></div>    
</div>
<script>
//IE7-浏覽器傳回<div id="div0">,其他浏覽器傳回<body>
console.log(test.offsetParent);
</script>

<div id="div0" style="position:absolute;">
    <div id="div1" style="display:inline-block;">
        <div id='test'></div>    
    </div>    
</div>
<script>
//IE7-浏覽器傳回<div id="div1">,其他浏覽器傳回<div id="div0">
console.log(test.offsetParent);
</script>

<div id="div0" style="display:inline-block;">
    <div id="div1" style="position:absolute;">
        <div id='test'></div>    
    </div>    
</div>
<script>
//所有浏覽器都傳回<div id="div1">
console.log(test.offsetParent);
</script>
           

偏移量

  偏移量共包括offsetHeight、offsetWidth、offsetLeft、offsetTop這四個屬性

offsetWidth

  offsetWidth表示元素在水準方向上占用的空間大小,無機關(以像素px計)

offsetWidth =  border-left-width + padding-left + width + padding-right + border-right-width; 
           

offsetHeight

  offsetHeight表示元素在垂直方向上占用的空間大小,無機關(以像素px計)

offsetHeight =  border-top-width + padding-top + height + padding-bottom + border-bottom-width
           
<div id="test" style="width:100px; height:100px; padding:10px; margin:10px; border:1px solid black;"></div>    
<script>
//122=1+10+100+10+1
console.log(test.offsetWidth);
console.log(test.offsetHeight);
</script>
           

  [注意]如果存在垂直滾動條,offsetWidth也包括垂直滾動條的寬度;如果存在水準滾動條,offsetHeight也包括水準滾動條的高度

<div id="test" style="width:100px; height:100px; padding:10px; margin:10px; border:1px solid black; overflow: scroll;"></div>    
<script>
//IE8-浏覽器将垂直滾動條的寬度計算在width寬度和height高度中,width和height的值仍然是100px;
//而其他浏覽器則把垂直滾動條的寬度從width寬度中移出,把水準滾動條的高度從height高度中移出,則滾動條寬度為17px,width寬度和height高度為剩下的83px

if(window.getComputedStyle){
    console.log(getComputedStyle(test).width,getComputedStyle(test).height)//83px
}else{
    console.log(test.currentStyle.width,test.currentStyle.height);//100px
}
//122=1+10+100+10+1
console.log(test.offsetWidth,test.offsetHeight);
</script>
           

offsetTop

  offsetTop表示元素的上外邊框至offsetParent元素的上内邊框之間的像素距離

offsetLeft

  offsetLeft表示元素的左外邊框至offsetParent元素的左内邊框之間的像素距離

<div id="out" style="padding: 5px;position: relative;margin: 6px;border:1px solid black">
    <div id="test" style="width:100px; height:100px; margin:10px;"></div>        
</div>
<script>
//15=test.marginTop(10) + out.paddingTop(5)
alert(test.offsetTop);
//15=test.marginLeft(10) + out.paddingLeft(5)
alert(test.offsetLeft);
</script>
           

IE7-Bug

  IE7-浏覽器在offsetTop屬性的處理上存在bug

  【1】若父級設定position: relative,則在IE7-浏覽器下,offsetTop值為offsetParent元素的paddingBottom值

<div id="out" style="padding: 5px;position: relative;">
    <div id="test" style="width:100px; height:100px; margin:10px;"></div>        
</div>
<script>
//其他浏覽器傳回15(5+10),而IE7-浏覽器傳回5
console.log(test.offsetTop);
</script>
           

 【2】若父級設定position: aboslute(或其他觸發haslayout的條件),offsetTop值為offsetParent元素的paddingBottom值和目前元素的marginTop值的較大值

<div id="out" style="padding: 5px;position:absolute;">
    <div id="test" style="width:100px; height:100px; margin:10px;"></div>        
</div>
<script>
//其他浏覽器傳回15(5+10),而IE7-浏覽器傳回10(10和5的較大值)
console.log(test.offsetTop);
</script>
           

頁面偏移

  要知道某個元素在頁面上的偏移量,将這個元素的offsetLeft和offsetTop與其offsetParent的相同屬性相加,并加上offsetParent的相應方向的邊框,如此循環直到根元素,就可以得到元素到頁面的偏移量

  [注意]在預設情況下,IE8-浏覽器下如果使用currentStyle()方法擷取<html>和<body>(甚至普通div元素)的邊框寬度都是medium,而如果使用clientLeft(或clientTop)擷取邊框寬度,則是實際的數值

html,body{border: 0;}
body{margin:0;}
           
function getElementLeft(element){
    var actualLeft = element.offsetLeft;
    var current = element.offsetParent;
    while(current != null){
        actualLeft += current.offsetLeft + current.clientLeft;
        current = current.offsetParent;
    }
    return actualLeft + 'px';
}
function getElementTop(element){
    var actualTop = element.offsetTop;
    var current = element.offsetParent;
    while(current != null){
        actualTop += current.offsetTop + current.clientTop;
        current = current.offsetParent;
    }
    return actualTop + 'px';
}
           
<div style="padding: 20px;border:1px solid black;position:absolute;">
    <div id="test" style="width:100px; height:100px; margin:10px;"></div>        
</div>        
<script>
//其他浏覽器傳回31(10+20+1),而IE7-浏覽器傳回21((20和10的較大值)+1)
console.log(getElementTop(test));
//所有浏覽器傳回31(10+20+1)
console.log(getElementLeft(test));
</script>
           

注意事項

  【1】所有偏移量屬性都是隻讀的

<div id="test" style="width:100px; height:100px; margin:10px;"></div>        
<script>
console.log(test.offsetWidth);//100
//IE8-浏覽器會報錯,其他浏覽器則靜默失敗
test.offsetWidth = 10;
console.log(test.offsetWidth);//100
</script>
           

 【2】如果給元素設定了display:none,則它的偏移量屬性都為0

<div id="test" style="width:100px; height:100px; margin:10px;display:none"></div>
<script>
console.log(test.offsetWidth);//0
console.log(test.offsetTop);//0
</script>
           

【3】每次通路偏移量屬性都需要重新計算

<div id="test" style="width:100px; height:100px; margin:10px;"></div>        
<script>
console.time("time");
for(var i = 0; i < 100000; i++){
    var a = test.offsetWidth;
}
console.timeEnd('time');//65.129ms
</script>
           
<div id="test" style="width:100px; height:100px; margin:10px;"></div>        
<script>
console.time("time");
var a = test.offsetWidth;
for(var i = 0; i < 100000; i++){
    var b = a;
}
console.timeEnd('time');//1.428ms
</script>
           

由上面代碼對比可知,重複通路偏移量屬性需要耗費大量的性能,是以要盡量避免重複通路這些屬性。如果需要重複通路,則把它們的值儲存在變量中,以提高性能。 

繼續閱讀