JQ的offset().top與JS的getBoundingClientRect區別詳解,JS獲取元素距離視窗頂部可變距離

 壹 ❀ 引css

我在 JQ的offset().top與js的offsetTop區別詳解 這篇博客中詳細分析了JQ方法offset().top與JS屬性offsetTop的區別,並得出了一條offset().top = offsetTop - scrollTop的結論,不過此結論只適用於監聽元素滾動條,而window的滾動條並不知足。那麼在滾動window滾動條時如何獲取元素距離視窗頂部的距離呢,這就不得說說本文的主角getBoundingClientRect方法。html

 貳 ❁ 關於getBoundingClientRect()jquery

咱們能夠先拷貝下面的代碼,動手起來跟着操做一遍,印象會深入,須要引入JQ,這裏提供一個靜態資源地址,進去搜索JQ直接複製地址引入便可:瀏覽器

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <link rel="stylesheet" href="css/demo.css">
</head>
<body>
    <div class="child"></div>
</body>
<script src="https://cdn.staticfile.org/jquery/3.4.1/jquery.js"></script>
<script src="js/app.js"></script>
</html>
* {
    padding: 0;
    margin: 0;
    list-style: none;
    outline: none;
}

.child {
    margin-top: 200px;
    margin-left: 200px;
    height: 200px;
    width: 200px;
    background: #bbded6;
    border: 5px solid #8ac6d1;
}
// JS getBoundingClientRect()
let child = document.querySelector('.child');
console.log(child.getBoundingClientRect());

//JQ offset()
// let son = $('.child');
// son.offset();

// JS offsetTop
// child.offsetTop;

這裏咱們在頁面定義了一個寬高各200px且包含5px邊框的盒子,因爲沒設置box-size = ’border-box'屬性,因此盒子總寬高爲210px,這裏咱們直接打印出getBoundingClientRect方法結果,以下:app

能夠看到getBoundingClientRect()返回了一個 DOMRect 對象,該對象包含了元素多個屬性,其中最顯眼的widthheight毫無懸念就是元素寬高,除此以外還包含top,bottom,right,leftx,y屬性。ide

不難猜出,topleft爲元素左上頂點距離視窗頂端與左側距離,而rightbottom爲右下頂點距離視窗左側與頂端距離。而xleft一致,ytop一致。ui

如今修改代碼,將css中的margin-top修改成1000px,同時使用scroll事件打印getBoundingClientRecttop值與滾動條距離,其它不變,像這樣:spa

window.onscroll = function () {
    //輸出top值與滾動條距離
    console.log(child.getBoundingClientRect().top, document.documentElement.scrollTop);
};

當滾動條滾動,能夠發現getBoundingClientRect().top值加上document.documentElement.scrollTop的值終等於1000,而這1000正是元素距離視窗頂部的距離。3d

如今將JQ的代碼與輸出offsetTop的代碼取消註釋,並加入到scroll事件中,再次滾動滾動條像這樣:code

// JS getBoundingClientRect()
let child = document.querySelector('.child');
let son = $('.child');
window.onscroll = function () {
    //輸出getBoundingClientRect的top值,JQ的offset().top與offsetTop
  console.log(child.getBoundingClientRect().top,son.offset().top,child.offsetTop);
};

能夠看到getBoundingClientRect().top是順着滾動條下移慢慢變小的,畢竟元素距離視窗頂部愈來愈近了,而offset().topoffsetTop一直保持1000,爲何呢?

首先,咱們知道offsetTop獲取的是元素距離本身最近的offsetParent(position爲非static且距離本身最近的祖先元素)的距離,且這個距離不隨滾動條滾動變化,也就是說這個距離開始是多少就是多少,是個恆定值。

而JQ的offset().top獲取的是元素距離文檔頂端的距離。怎麼去理解這個文檔呢,咱們把瀏覽器網頁可讀範圍比喻成一幅畫,這幅畫包含了html,因此若是html內容越多(好比給html設置上margin),這幅畫就會越長;而視窗呢能夠比喻成一塊玻璃,咱們透過玻璃看這幅畫,若是畫的高度比玻璃還高那就有了滾動條,當滾動往下拉時,等同於玻璃位置不變,可是畫會往上移。

知道這個概念後,咱們再來想一想上面例子爲何offset().top一直不變,當滾動條下拉,畫往上移,而畫中的元素是隨着畫一塊兒運動的,很明顯該元素相對畫頂端的距離也一直沒變,這下總知道爲啥是1000了吧。

getBoundingClientRect獲取的是元素距離視窗頂端的距離,當畫上移,元素確定距離視窗頂端愈來愈近,因此這個距離必定愈來愈小。

 叄 ✿ getBoundingClientRect與offset().top的區別

那麼到這,咱們知道了getBoundingClientRect參照是視窗頂端,而JQ的offset().top參照的是文檔,二者參照對象不一樣。

當監聽的是window的滾動條時,元素的getBoundingClientRect().top會原來越小,而offset().top一直不變。

當監聽某個元素的滾動條時,元素的getBoundingClientRect().top會與offset().top保持一致,好比我讓一個ul包含了多個li,滾動ul的滾動條時,獲取第一個li的相關屬性,有興趣能夠將下面的代碼替換一下:

HTML
<ul>
    <li style="background: orange;">1</li>
    <li style="background: black;">2</li>
    <li style="background: blueviolet;">3</li>
    <li style="background: pink;">4</li>
</ul>

CSS
* {
    padding: 0;
    margin: 0;
    list-style: none;
    outline: none;
    box-sizing: border-box;
}

ul {
    width: 200px;
    height: 100px;
    overflow-y: scroll;
    margin: 100px;

}

li {
    width: 100px;
    height: 300px;
    line-height: 300px;
    text-align: center;
}

JS
let parent = document.querySelector('ul');
let child = document.querySelectorAll('li')[0];
parent.onscroll = function () {
    //輸出getBoundingClientRect的top值,JQ的offset().top與offsetTop
    console.log(child.getBoundingClientRect().top, $(child).offset().top, child.offsetTop);
};
View Code

能夠看到getBoundingClientRect().topoffset().top的值徹底一致。

 肆 ❤ 獲取元素距離距離視窗頂部的可變距離

樓層導航,懶加載,返回頂部按鈕等等,只要涉及scroll事件,都沒法避免的要去計算某個元素距離視窗頂部的距離,通過前文的分析,不論是監聽window滾動條仍是元素滾動條,其實都有兩種可行方法。

若是是監聽的是window的滾動條,那麼可使用:

window.onscroll = function () {
    可變距離 = document.querySelector('元素').getBoundingClientRect().top
};

其次能夠獲取元素的offsrtTop減去滾動條距離,前提是得保證元素的offsetParent爲html元素或者body:

var offsetTop = document.querySelector('元素').offsetTop;
window.onscroll = function () {
    可變距離 = offsetTop - document.documentElement.scrollTop;
};

若是監聽的是元素的滾動條,獲取元素內子元素距離視窗的高度可使用JQ的offset().top:

document.querySelector('父元素').onscroll = function () {
    子元素可變距離 = $('子元素元素').offset().top;
};

其次可使用子元素的offsetTop減去父元素滾動條距離,固然你也得保證子元素的offsetParent爲html或body:

var parent = document.querySelector('父元素');
var son = document.querySelector('子元素');
parent.onscroll = function () {
    子元素可變距離 = son.offsetTop - parent.scrollTop;
};

 伍 ☸ 總

那麼結合文章開頭的另外一篇博客以及本文,咱們詳細介紹了JQ的offset().top與JS的offsetTop以及getBoundingClientRect的區別:

咱們知道了offset().top參照對象是文檔上邊界,當監聽window滾動條,它的效果與offsetTop相似,都是固定不變的值,畢竟在元素上移時,總體的文檔也上移了。

咱們知道offsetTop的參照對象是一個可變的offsetParent,並且獲得的值永遠不變。

咱們還知道了好用的getBoundingClientRect方法,它的參照對象是視窗頂端,無論滾動條是window仍是元素的,咱們能夠時時拿到可變尺寸。

固然咱們還了解了特定狀況下,使用offsetTop - scrollTop同樣能拿到這個可變值。

那麼到這裏,本文結束。

相關文章
相關標籤/搜索