相信不少小夥伴在工做中都會遇到圖片請求數量過多,致使出現頁面會出現卡頓的狀況,在咱們前端開發工做中,頁面的渲染速度是十分重要的。
談到這,咱們都知道其中最大的一個問題就是圖片加載速度
會拖累整個頁面體驗。不少頁面,內容很豐富,頁面很長,圖片較多,好比說各類商城頁面。這些頁面圖片數量多,並且比較大,少說百來K,多則上兆。有的時候沒有必要一次性加載完。不然常會出現加載半張圖片或是殘缺,網速很差的有時候還會出現圖片加載不出來等問題。
那麼咱們可使用現有的技術,先顯示可視區域
中的圖片,再使剩餘圖片未顯示的圖片和滾動條事件
作交互,「滑到你,你再顯示出來」,這也就是咱們常說的懶加載
,來咱們看一下關於懶加載的定義。前端
懶加載
(Load On Demand)是一種獨特而又強大的數據獲取
方法,它可以在用戶滾動頁面
的時候自動獲取更多的數據,而新獲得的數據不會影響原有數據的顯示,同時最大程度上減小服務器端的資源耗用。git
關於懶加載的方式有不少種,在這裏只會着重介紹其中兩種,傳統的懶加載方式
以及交叉觀察者
這兩種方式。github
傳統的
懶加載
方式其實就是經過監聽滾動軸的變化,去請求出如今可視區域的圖片。數組
將頁面中的
img
標籤src
指向一張小圖片或者src
爲空,而後定義data-src
(這個屬性能夠自定義命名,我採用data-src
)屬性指向真實的圖片。
瀏覽器
<div class="box">
// 在這裏咱們使用自定義屬性data-src存儲真實的圖片地址
<img style="margin-top: 600px;" class="img" src=""
data-src="https://user-gold-cdn.xitu.io/2019/9/7/16d0a7d1e26e2947?w=533&h=300&f=jpeg&s=44672"
alt="">
<img class="img" src=""
data-src="https://user-gold-cdn.xitu.io/2019/9/7/16d0a7d1e28ba479?w=500&h=463&f=jpeg&s=10435"
alt="">
<img class="img" src=""
data-src="https://user-gold-cdn.xitu.io/2019/9/7/16d0a7d1e5b3c69c?w=579&h=300&f=jpeg&s=23132"
alt="">
<img class="img" src=""
data-src="https://user-gold-cdn.xitu.io/2019/9/7/16d0a7d1e60d6bc9?w=500&h=394&f=jpeg&s=27013"
alt="">
<img class="img" src=""
data-src="https://user-gold-cdn.xitu.io/2019/9/7/16d0a7d1e5ac147c?w=500&h=313&f=jpeg&s=29734"
alt="">
<img class="img" src=""
data-src="https://user-gold-cdn.xitu.io/2019/9/7/16d0a7d1e5d0a8ef?w=428&h=600&f=jpeg&s=37727"
alt="">
<img class="img" src=""
data-src="https://user-gold-cdn.xitu.io/2019/9/7/16d0a7d2033996bc?w=500&h=325&f=jpeg&s=9951"
alt="">
</div>
複製代碼
.box {
width: 800px;
height: 400px;
border: 1px solid;
overflow: auto;
}
.img {
width: 100px;
height: 100px;
border: 1px solid;
display: block;
margin: 40px auto;
}
複製代碼
在這裏咱們基本能夠實現一個這樣的界面bash
1.首先咱們先去獲取父級元素以及子元素
const box = document.querySelector('.box');
const imgs = document.querySelectorAll('.img');
2.監聽父級滾動軸變化
box.addEventListener('scroll', handleListenScroll);
3.實現監聽函數
function handleListenScroll() {
//獲取父級滾動軸距離頂部距離
var scrollTop = box.scrollTop;
//獲取父級高度
var divHeight = box.clientHeight;
for (var i = 0; i < imgs.length; i++){
if (imgs[i].offsetTop < divHeight + scrollTop) {
imgs[i].src = imgs[i].getAttribute('data-src');
}
}
}
這樣一個簡單的懶加載就實現了,咱們看下效果。
複製代碼
若是直接將函數綁定在scroll事件上,當頁面滾動時,函數會被高頻觸發,這很是影響瀏覽器的性能。服務器
所謂
節流
,就是當持續觸發事件時,保證必定時間段內只調用一次事件處理函數。這裏也許會有小夥伴說了,防抖
呢?先說一下防抖
的概念吧,當持續觸發事件時,必定時間段內沒有再觸發事件,事件處理函數纔會執行一次,若是設定的時間到來以前,又一次觸發了事件,就從新開始延時。根據咱們的場景,顯然在這裏使用防抖
是不太合適的。app
box.addEventListener('scroll', throttle(handleListenScroll, 500));
//節流實現
function throttle(func, delay) {
var previous = 0;
return function () {
let now = Date.now();
let context = this;
let args = arguments;
if (now - previous > delay) {
func.apply(context, args);
previous = now;
}
};
}
複製代碼
小tip 在使用的時候咱們也能夠給每一個圖片一個默認圖片,等圖片出如今可視區域的時候進行一個替換。異步
交叉觀察者
其實就是利用IntersectionObserver
接口 (從屬於Intersection Observer API
) 提供了一種異步觀察目標元素與其祖先元素或頂級文檔視窗(viewport
)交叉狀態的方法。祖先元素與視窗(viewport
)被稱爲根(root
)。函數
用通俗的話來說就是判斷目標元素有沒有和父級元素產生交叉行爲,一張圖說明一切,畫的醜,請見諒~~
呃呃呃, IE幾乎全軍覆沒,不過,有官方提供過的polyfill
,啥都不用怕,點這裏。
屬性 | 介紹 |
---|---|
root | 所監聽對象的具體祖先元素(element)。若是未傳入值或值爲null,則默認使用頂級文檔的視窗。 |
rootMargin | 計算交叉時添加到根(root)邊界盒bounding box的矩形偏移量, 能夠有效的縮小或擴大根的斷定範圍從而知足計算須要 |
thresholds | 一個包含閾值的列表, 按升序排列, 列表中的每一個閾值都是監聽對象的交叉區域與邊界區域的比率。 |
方法 | 介紹 |
---|---|
disconnect() | 使IntersectionObserver對象中止監聽工做 |
observe() | 使IntersectionObserver開始監聽一個目標元素。 |
takeRecords() | 返回全部觀察目標的IntersectionObserverEntry對象數組。 |
unobserve() | 使IntersectionObserver中止監聽特定目標元素。 |
1.新建一個IntersectionObserver
對象。
const observer = new IntersectionObserver(entries => {
// 發生交叉目標元素集合
console.log(entries);
}, option);
在這裏callback會返回給咱們當前已監聽而且發生了交叉的目標集合,咱們看一下具體信息。
複製代碼
屬性 | 介紹 |
---|---|
boundingClientRect | 空間信息 |
target | 目標元素 |
isIntersecting | 是否發生交叉 |
2.監聽目標元素
const box = document.querySelector('.box');
const imgs = document.querySelectorAll('.img');
const observer = new IntersectionObserver(entries => {
// 發生交叉目標元素集合
entries.forEach(item => {
// 判斷是否發生交叉
if (item.isIntersecting) {
// 替換目標元素Url
item.target.src = item.target.dataset.src;
// 取消監聽此目標元素
observer.unobserve(item.target);
}
});
}, {
root: box, // 父級元素
rootMargin: '20px 0px 100px 0px' // 設置偏移 咱們能夠設置在目標元素距離底部100px的時候發送請求
});
imgs.forEach(item => {
// 監聽目標元素
observer.observe(item);
});
複製代碼
以上就是使用
IntersectionObserver
實現懶加載的過程,是否是很簡單呢,在這裏咱們再也不須要去監聽滾動條的變化,只須要根據返回給咱們的元素集合就能夠實現。還要記住必須是子元素跟父元素髮生交叉,是不能夠去檢查兩個非父子關係的交叉的狀況哦~~
綜上 就是我對於懶加載一點小看法,也但願將來咱們的頁面更加流暢,so,先從懶加載開始吧~~。其實懶加載只是經過IntersectionObserver
實現的一點小功能,IntersectionObserver
還能夠幫咱們實現吸頂
、觸底
這些功能,感興趣的小夥伴能夠去試試哦。最後,文中若有錯誤,歡迎在評論區指正,若是這篇文章幫助到了你,歡迎點贊👍和關注,😀。