壹 ❀ 引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 對象,該對象包含了元素多個屬性,其中最顯眼的width與height毫無懸念就是元素寬高,除此以外還包含top,bottom,right,left與x,y屬性。ide
不難猜出,top和left爲元素左上頂點距離視窗頂端與左側距離,而right與bottom爲右下頂點距離視窗左側與頂端距離。而x與left一致,y與top一致。ui
如今修改代碼,將css中的margin-top修改成1000px,同時使用scroll事件打印getBoundingClientRect的top值與滾動條距離,其它不變,像這樣: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().top與offsetTop一直保持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); };
能夠看到getBoundingClientRect().top與offset().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同樣能拿到這個可變值。
那麼到這裏,本文結束。