# 透過 lazy loading 延遲載入圖片
# Intersection Observer API
# 拆解步驟
- 不讓圖片正常載入
- 監視圖片元素,判斷它們是否進入到畫面中
- 元素進入畫面後,再載入圖片
# 不讓圖片正常載入
我們可以透過「完全不放路徑」的方法,也就是說連 src
這個屬性都沒有。取而代之的是叫做 data-src
的自訂資料屬性,我們把圖片網址暫時存在這邊。
圖片一旦沒了 src
,自然就不會載入。而等到我們真正需要載入圖片時,再把 data-src
的值取出來、塞回給 src
,這時候圖片拿到 src
,就會自動開始載入了。
<!-- 不放 src 屬性 -->
<img :data-src="'https://picsum.photos/500/500?random=' + item" />
1
2
2
# 監視圖片元素
- 首先創造一個
IntersectionObserver
instance - 傳入一個 callback function 給它,等偵測到元素進入畫面時 callback function 會被呼叫
- 使用 instance 的
observe
method 開始監視元素
const onEnterView = (entries, observer) => {
for (let entry of entries) {
// 判斷元素是否進入畫面
if (entry.isIntersecting) {
loadImage(entry.target);
// 取消監視元素
observer.unobserve(entry.target);
}
}
};
const watcher = new IntersectionObserver(onEnterView);
const lazyImages = document.querySelectorAll('.lazyloadImage__img.lazy');
for (let image of lazyImages) {
// 對每一個元素進行監視
watcher.observe(image);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 載入圖片
- 判斷目標是否進入畫面
- 確認目標進入畫面後,把
data-src
的值取出,放到src
- 移除等待載入的元素和狀態
- 用
observer.unobserve
取消監視元素
// 移除等待載入元素
const removeMockup = (event) => {
const mockup = event.target.previousElementSibling;
mockup.classList.remove('lazyloadImage--loading');
mockup.classList.add('lazyloadImage--fadeOut');
mockup.addEventListener('transitionend', mockup.remove);
};
// 載入圖片
const loadImage = (img) => {
img.previousElementSibling.classList.add('lazyloadImage--loading');
img.setAttribute('src', img.dataset.src);
img.removeAttribute('data-src');
img.addEventListener('load', removeMockup);
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
注意
圖片進入畫面後記得要 取消監視,否則等圖片載入完後,Intersection Observer 還是會持續監視元素、重複觸發 callback function。
試一試