摘要:在這里一次性做個總結,以用來判斷元素是否在可視區域以及用原生簡單實現懶加載。被隱藏在內容區域左側的像素數。比如上篇文章文字跑馬燈項目中的使用戳此跳轉小結只讀屬性,不包括滾動條。
個性簽名: 生如夏花,逝如冬雪;人生如此,何悔何怨。
前言: 經常需要計算元素的大小或者所在頁面的位置,offsetWidth,clientWidth,scrollWidth,scrollTop這幾個關鍵字的出現更是家常便飯,每次碰到都需要事先實驗一番。為了下次開發提高效率。在這里一次性做個總結,以用來判斷元素是否在可視區域以及用原生js簡單實現懶加載。文末有個簡單的懶加載實現的demo,有需要的可以看一下。
目錄
工欲善其事,必先利其器。在判斷元素是否在可視區域實現簡單的原生懶加載前,我們先簡單回顧下以下幾個關鍵的概念。
ps: 如果你對這些概念已經比較熟悉了,可以直接跳到第五點查看關鍵代碼示例。
1. 偏移量偏移量(offset dimension),元素的可見大小由其高度、寬度決定,包括所有內邊距、滾動條和邊框大小(注意,不包括外邊距)。通過下列4個屬性可以取得元素的偏移量。
偏移量 | 概念 | 公式 |
---|---|---|
offsetHeight | 元素在垂直方向上占用的空間大小,以像素計。包括元素的高度、(可見的) 水平滾動條的高度、上邊框高度和下邊框高度。 | offsetHeght = content + padding + border + scrollX |
offsetWidth | 元素在水平方向上占用的空間大小,以像素計。包括元素的寬度、(可見的)垂 直滾動條的寬度、左邊框寬度和右邊框寬度。 | offsetWidth = content + padding + border + scrollY |
offsetLeft | 元素的左外邊框至**包含元素的左內邊框之間的像素距離。 | |
offsetTop | 元素的上外邊框至包含元素的上內邊框之間的像素距離。 |
其中,offsetLeft 和 offsetTop 屬性與包含元素有關,包含元素的引用保存在 offsetParent 屬性中。**offsetParent 屬性不一定與 parentNode 的值相等。
如下圖顯示
注意: 所有這些偏移量屬性都是只讀的,而且每次訪問它們都需要重新計算。因此,應該盡量避免重復訪問這些屬性;如果需要重復使用其中某些屬性的值,可以將它們保 存在局部變量中,以提高性能。
這也是上篇文章文字跑馬燈項目中(戳此跳轉),為什么增加padding后,textWidth需要重新獲取的原因
小結
偏移量: 只讀屬性;包括滾動條和邊框,不包括外邊距。
2. 客戶區大小客戶區大小是只讀的,每次訪問都要重新計算的。
客戶區大小 | 概念 | 公式 |
---|---|---|
clientWidth | clientWidth 屬性是元素內容區寬度加 上左右內邊距寬度; | clientWidth = content + padding |
clientHeight | 元素內容區高度加上上下內邊距高度 | clientHeight = content + padding |
最常用到這些屬性的情況,就是確定瀏覽器視口大小的時候(在 IE7 之前的版本中)。如下面的例子所示:
function getViewport(){ // 檢查 document.compatMode 屬性,以確定瀏覽器是否運行在混雜模式。 // Safari3.1 之前的版本不支持這個屬性,因此就會自動執行 else 語句 if (document.compatMode == "BackCompat"){ return { width: document.body.clientWidth, height: document.body.clientHeight }; } else { return { width: document.documentElement.clientWidth, height: document.documentElement.clientHeight }; } }
小結
客戶區大小: 只讀屬性;不包括滾動條和邊框,不包括外邊距。
3. 滾動大小概念 | |
---|---|
scrollHeight | 在沒有滾動條的情況下,元素內容的總高度。 |
scrollWidth | 在沒有滾動條的情況下,元素內容的總寬度。 |
scrollLeft | 被隱藏在內容區域左側的像素數。通過設置這個屬性可以改變元素的滾動位置。 |
scrollTop | 被隱藏在內容區域上方的像素數。通過設置這個屬性可以改變元素的滾動位置。 |
scrollWidth 和 scrollHeight 主要用于確定元素內容的實際大小。
scrollLeft 和 scrollTop屬性既可以確定元素當前滾動的狀態,也可以設置元素的滾動位 置。在元素尚未被滾動時,這兩個屬性的值都等于 0。如果元素被垂直滾動了,那么 scrollTop 的值 會大于 0,且表示元素上方不可見內容的像素高度。如果元素被水平滾動了,那么 scrollLeft 的值會 大于 0,且表示元素左側不可見內容的像素寬度。這兩個屬性都是可以設置的,因此將元素的 scrollLeft 和 scrollTop 設置為 0,就可以重置元素的滾動位置。比如:上篇文章文字跑馬燈項目中scrollLeft的使用(戳此跳轉)
小結
只讀屬性,不包括滾動條、border。
4. 確定元素大小getBoundingClientRect
getBoundingClientRect的兼容性寫法:
對于不支持 getBoundingClientRect()的瀏覽器,可以通過其他手段取得相同的信息。一般來 說,right 和 left 的差值與 offsetWidth 的值相等,而 bottom 和 top 的差值與 offsetHeight 相等。綜合上述,就可以創建出下面這個跨瀏覽器的函數:
function getElementLeft(element){ var actualLeft = element.offsetLeft; var current = element.offsetParent; while (current !== null){ actualLeft += current.offsetLeft; current = current.offsetParent; } return actualLeft; } function getElementTop(element){ var actualTop = element.offsetTop; var current = element.offsetParent; while (current !== null){ actualTop += current. offsetTop; current = current.offsetParent; } return actualTop; } function getBoundingClientRect(element) { var scrollTop = document.documentElement.scrollTop; var scrollLeft = document.documentElement.scrollLeft; if (element.getBoundingClientRect) { if (typeof arguments.callee.offset != "number") { var temp = document.createElement("div"); temp.style.cssText = "position:absolute;left:0;top:0;"; document.body.appendChild(temp); arguments.callee.offset = -temp.getBoundingClientRect().top - scrollTop; document.body.removeChild(temp); temp = null; } var rect = element.getBoundingClientRect(); var offset = arguments.callee.offset; return { left: rect.left + offset, right: rect.right + offset, top: rect.top + offset, bottom: rect.bottom + offset }; } else { var actualLeft = getElementLeft(element); var actualTop = getElementTop(element); return { left: actualLeft - scrollLeft, right: actualLeft + element.offsetWidth - scrollLeft, top: actualTop - scrollTop, bottom: actualTop + element.offsetHeight - scrollTop } } }5.判斷元素是否在可視區域
知道了元素的大小以及所位于的區域外,我們可以做些什么呢?我們可以通過上面學到的知識點來檢測元素是否在可視區域,再說大一點,這也是懶加載圖片的實現原理。
5.1 第一種方法公式: el.offsetTop - document.documentElement.scrollTop <= viewPortHeight
function isInViewPortOfOne (el) { // viewPortHeight 兼容所有瀏覽器寫法 const viewPortHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight const offsetTop = el.offsetTop const scrollTop = document.documentElement.scrollTop const top = offsetTop - scrollTop console.log("top", top) // 這里有個+100是為了提前加載+ 100 return top <= viewPortHeight + 100 }5.2 第二種方法
公式: el.getBoundingClientReact().top <= viewPortHeight
其實, el.offsetTop - document.documentElement.scrollTop = el.getBoundingClientRect().top, 利用這點,我們可以用下面代碼代替方法一
function isInViewPortOfTwo (el) { const viewPortHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight const top = el.getBoundingClientRect() && el.getBoundingClientRect().top console.log("top", top) return top <= viewPortHeight + 100 }5.3 第三種方法
公式: intersectionRatio > 0 && intersectionRatio <= 1
// 定義一個交叉觀察器 const io = new IntersectionObserver(ioes => { ioes.forEach(ioe => { const el = ioe.target const intersectionRatio = ioe.intersectionRatio if (intersectionRatio > 0 && intersectionRatio <= 1) { loadImg(el) io.unobserve(el) } el.onload = el.onerror = () => io.unobserve(el) }) }) // 執行交叉觀察器 function isInViewPortOfThree (el) { io.observe(el) }5.4 兼容性比較
在兼容性方面,我們知道越原始的方法兼容性是最好的,那么第二種方法和第三種方法能否代替第三種方法呢?我們來看看。
從caniuse的數據來看,getBoundingClientReact的適配情況很樂觀了。
所以,如果在移動端和桌面端都要做兼容適配的話,方法二完全可以代替方法一進行適配了。如果僅僅是桌面端適配(比如運營后臺),我們或許可以嘗試下新的IntersectionObserver方法,畢竟IntersectionObserver里面還有更多豐富的功能等著我們去體驗呢。
5.5 實例有時,我們希望某些靜態資源(比如圖片),只有用戶向下滾動,它們進入視口時才加載,這樣可以節省帶寬,提高網頁性能。這就叫做"惰性加載",也稱為懶加載。
惰性加載預覽DEMO(放入你的本地圖片即可通過更換不同方法實現懶加載)
------------------------------ 華麗的分割線 ---------------------------
ps: 有公眾號大佬想減輕日常寫推文的時間消耗,收購技術原創文章的稿子放在自己公眾號展示推送的,可以聯系找我合作哈。(在公眾號里可以查到我的聯系方式)
關于我
我的github主頁(點擊進入)
我的掘金主頁(點擊進入)
我的簡書主頁(點擊進入)
我的公眾號(點擊進入或者掃描下方二維碼)
參考
原生JS實現最簡單的圖片懶加載
JavaScript高級程序設計
IntersectionObserver API 使用教程
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/114299.html
摘要:在這里一次性做個總結,以用來判斷元素是否在可視區域以及用原生簡單實現懶加載。被隱藏在內容區域左側的像素數。比如上篇文章文字跑馬燈項目中的使用戳此跳轉小結只讀屬性,不包括滾動條。 個性簽名: 生如夏花,逝如冬雪;人生如此,何悔何怨。 前言: 經常需要計算元素的大小或者所在頁面的位置,offsetWidth,clientWidth,scrollWidth,scrollTop這幾個關鍵字的出...
摘要:在這里一次性做個總結,以用來判斷元素是否在可視區域以及用原生簡單實現懶加載。被隱藏在內容區域左側的像素數。比如上篇文章文字跑馬燈項目中的使用戳此跳轉小結只讀屬性,不包括滾動條。 個性簽名: 生如夏花,逝如冬雪;人生如此,何悔何怨。 前言: 經常需要計算元素的大小或者所在頁面的位置,offsetWidth,clientWidth,scrollWidth,scrollTop這幾個關鍵字的出...
摘要:除了坐標問題外,該方法只能返回頂層元素,也就是在有個元素重疊的情況下,只能返回最上層的元素。 先說一下這個方法的參數 elemntFromPoint(x,y);//傳入坐標值,返回當前頁面上包含該坐標點的頂層元素 注意2點,坐標值和頂層元素 先說坐標,因為不同的人理解是不一樣的,也就造就了這個方法在不同的瀏覽器中表現是不一樣的,所以在傳入坐標時就分 整體頁面坐標 和 可視區域坐標,我們...
摘要:構造函數調用時,需要給它傳一個回調函數。當監聽的元素進入可視區域或者從可視區域離開時,回調函數就會被調用。構造函數的返回值是一個觀察器實例。它是一個數組,每個成員都是一個門檻值,默認為,即交叉比例達到時觸發回調函數。 IntersectionObserve這個API,可能知道的人并不多(我也是最近才知道...),這個API可以很方便的監聽元素是否進入了可視區域。 * { marg...
閱讀 1093·2021-10-12 10:11
閱讀 876·2019-08-30 15:53
閱讀 2286·2019-08-30 14:15
閱讀 2961·2019-08-30 14:09
閱讀 1197·2019-08-29 17:24
閱讀 972·2019-08-26 18:27
閱讀 1282·2019-08-26 11:57
閱讀 2145·2019-08-23 18:23