1. 程式人生 > >JQ的offset().top與js的offsetTop區別詳解

JQ的offset().top與js的offsetTop區別詳解

一、前言

最近在做一個圖片懶載入的外掛,就縱軸(Y軸)而言,我需要時時獲取圖片的上偏移量,好判斷是否已進入檢視區域,而我所理解的是offsetTop應該是跟offset().top一樣的,然後陷入了因為不瞭解它們區別,而帶來BUG的死坑。這裡通過實驗整理,做個清晰好懂的筆記,如果你也想弄清,建議複製我的程式碼跟著操作,印象會更為深刻。

二、offset().top與offsetTop什麼意思?它們都是相對誰的上偏移量?

offset().top是JQ的方法,需要引入JQ才能使用,它獲取的是你繫結元素上邊框相對於html上邊界的偏移量。

offsetTop是原生JS的方法,它獲取的是你繫結元素上邊框相對離自己最近且position屬性為非static的祖先元素的偏移量(後面會具體解釋)。

區別一:offset().top與offsetTop偏移量參照物件不同,offset().top始終是html,而offsetTop參照的物件是可變的。

大家可以先拷貝下面程式碼:

html部分
<ul class="contain">
    <li><div></div></li>
   <li><div></div></li>
<li><div></div></li> <li><div></div></li> </ul> css部分 body{ position:relative; padding:
0; margin:0; /* display: table; */ } .contain{ list-style: none; height: 1000px; width: 800px; overflow: auto; margin-top:200px;
background-color:#ebc38d; } .contain
>li{ margin-bottom: 10px; } .contain>li>div{ background-color: #e4393c; width: 300px; height: 400px; } js部分
var ul = document.querySelector(".contain"); var div = document.querySelectorAll("div")[0]; function demo() { var top1 = div.offsetTop;//第一個div的上偏移量 var top2 = $(div).offset().top;//第一個div的上偏移量 var top3 =ul.scrollTop;//ul自己的滾動條已滾動的距離,預設是0,往下滾動慢慢變大 //我的猜測 top2 = top1 - top3; console.log(top2, top1, top3); }

demo()
ul.addEventListener("scroll", demo);

html自己生成補全,記得引入JQ,這裡提供一個靜態資源庫,直接複製JQ地址引入就可以了。

Staticfile CDN

在css中我為ul加了一個上邊距為200px,先不解決上邊距坍塌的問題,這會導致整個body區域距離頁頭有200px的空白區域,以方便區分body和html,如下圖html範圍和body範圍:

這是html的範圍

這是body的範圍,很明顯比html要矮出200px的空白區域:

開啟控制檯,我們可以看到輸出了200,0,0;

第一個200:offset().top的值是第一個div上邊界相對html的上偏移量,因為有200px的margin,所以是200;

第二個0:offsetTop的值第一個div上邊界相對body的上偏移量,因為從div往上找,第一個position屬性為非static的(relative,absolute,fixed其一)的祖先元素是body,所以相對body。

 第三個0:scrollTop的值容器ul滾動條滾動的距離,因為預設沒有滾動,所以是0;

我們來做下改變,將display:talbe的註釋取消,同時將body的position:relative屬性移動到html上,其它不變,像這樣:

我們可以看到此時輸出:200,200,0;

第一個200:offset().top的值還是第一個div相對html的上偏移量,因為margin的問題。

第二個200:offsetTop的值驗證了我們之前的概念,offsetTop的參照物件是第一個position不為static的祖先元素,此時被我們修改成了html;

第三個0:容器ul的滾動條距離。

我們將body的display:table的註釋去掉,將html的position屬性去掉並還給body。其它不變,像這樣,畢竟佈局中上margin坍塌本來就不合理:

此時的body已經跟html範圍相同,不存在200px空白區域,雖然offsetTop參照的是body,offset().top參照的是html,但從兩個參照物件的上邊界而言,可以理解為參照的是統一物件。

可以看到控制檯還是輸出200,200,0。

相同點:當無滾動條且offsetTop與offset().top參照物件相同時,它們獲取的值相同。

 區別二:offsetTop獲取的偏移量不隨滾動條滾動變化,但offset().top跟這滾動條變化

我們嘗試滾動ul的滾動條,觀察輸出值的變化

可以看到offset().top的值隨著滾動條滾動越變越小,因為第一個div的上邊界與html的上邊界越來越近了。

offsetTop的值從一開始的200一直就沒變化,不受滾動條影響。

而ul的scrollTop也隨著我們的滾動條往下拉,有了滾動距離,也在慢慢變大。很好理解不是嗎?

三、猜測:offset().top = offsetTop - scrollTop

JQ能拿到變化的上偏移量,原生JS怎麼拿這個變化的值呢?參照上面試驗,scrollTop變大的同時,offset().top也在隨之變小,只有 offsetTop恆定不變。

不用猜測了,大家將滾動輸出列印的數字做個計算,很明顯,第一個數字 = 第二個數字  - 第三個數字,就算offset().top為負數也一樣遵守規則:

那我們可以得出這樣一個規律:

當一個元素的offset().top與offsetTop的參照物件相同時,offset().top的值等於offsetTop的值減去scrollTop的值。

我們將body的display屬性註釋掉,像這樣

很明顯,因為margin坍塌的問題,body和html之間又多了200px的空白間隔區域,offset().top與offsetTop的參照物件這下就不同了,我們滾動滾動條可以看到規則就不適用了:

四、總結

offsetTop與offset().top相同點:

1.當無滾動條且offsetTop與offset().top參照物件相同時,它們獲取的值相同。

offsetTop與offset().top不同點:

1.offset().top與offsetTop偏移量參照物件不同,offset().top始終是html,而offsetTop參照的物件是可變的。

2.offsetTop獲取的偏移量不隨滾動條滾動變化,但offset().top跟這滾動條變化

一個規律:

1.當一個元素的offset().top與offsetTop的參照物件相同時,offset().top = offsetTop - scrollTop

還是建議大家能照著練一遍,要不了多少時間,印象也會更深刻,也歡迎大家的補充和糾正,畢竟我也可能有理解錯誤的地方。

轉載請標明出處,謝謝。好睏...........