[實作] 懶加載圖片 Lazy image
說明
圖片懶加載的核心技術是 IntersectionObserver 元素進入畫面判斷,主要是透過元素進入畫面時,執行 callback
再加載圖片。
好處
- 提升效能
- 首屏加載速度
操作說明
假設目標元素是 <img class="lazy-img">
初始的 src
會設置一個共同的默認圖片,而其屬性 data-src
設置真實的圖片位置,當目標元素可以被看見,就將 data-src
資料寫入 src
供載入圖片。
HTML
html
<div class="container">
<img
class="lazy-img"
src="https://liftlearning.com/wp-content/uploads/2020/09/default-image.png"
data-src="https://picsum.photos/id/111/200/300"
/>
<img
class="lazy-img"
src="https://liftlearning.com/wp-content/uploads/2020/09/default-image.png"
data-src="https://picsum.photos/id/222/200/300"
/>
<img
class="lazy-img"
src="https://liftlearning.com/wp-content/uploads/2020/09/default-image.png"
data-src="https://picsum.photos/id/221/200/300"
/>
<img
class="lazy-img"
src="https://liftlearning.com/wp-content/uploads/2020/09/default-image.png"
data-src="https://picsum.photos/id/444/200/300"
/>
<img
class="lazy-img"
src="https://liftlearning.com/wp-content/uploads/2020/09/default-image.png"
data-src="https://picsum.photos/id/555/200/300"
/>
<img
class="lazy-img"
src="https://liftlearning.com/wp-content/uploads/2020/09/default-image.png"
data-src="https://picsum.photos/id/666/200/300"
/>
</div>
js
js
// 將監聽的對象
const lazyImgAry = document.querySelectorAll('.lazy-img')
// 監體實體
const ob = new IntersectionObserver(targetEvent)
// 觸發的函式
function targetEvent(enterTarget, ob) {
console.log('target')
console.log(enterTarget)
enterTarget.forEach((targetImg) => {
// targetImg 目標元素是否進入畫面
if (targetImg.isIntersecting) {
const targetEl = targetImg.target
// attribute `data-src`內容 寫入 img src
targetEl.src = targetEl.dataset.src
targetEl.removeAttribute('data-src')
// 移除監聽
ob.unobserve(targetEl)
}
})
}
lazyImgAry.forEach((imgItem) => {
// 把元素加入監聽
ob.observe(imgItem)
})
完整 DEMO
html
<!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" />
<style>
.container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
img {
padding: 1rem 0;
height: 400px;
width: 100%;
object-fit: cover;
}
</style>
<title>Lazy Image</title>
</head>
<body>
<h1>Lazy Image</h1>
<div class="container">
<img
class="lazy-img"
src="https://liftlearning.com/wp-content/uploads/2020/09/default-image.png"
data-src="https://picsum.photos/id/111/200/300"
/>
<img
class="lazy-img"
src="https://liftlearning.com/wp-content/uploads/2020/09/default-image.png"
data-src="https://picsum.photos/id/222/200/300"
/>
<img
class="lazy-img"
src="https://liftlearning.com/wp-content/uploads/2020/09/default-image.png"
data-src="https://picsum.photos/id/221/200/300"
/>
<img
class="lazy-img"
src="https://liftlearning.com/wp-content/uploads/2020/09/default-image.png"
data-src="https://picsum.photos/id/444/200/300"
/>
<img
class="lazy-img"
src="https://liftlearning.com/wp-content/uploads/2020/09/default-image.png"
data-src="https://picsum.photos/id/555/200/300"
/>
<img
class="lazy-img"
src="https://liftlearning.com/wp-content/uploads/2020/09/default-image.png"
data-src="https://picsum.photos/id/666/200/300"
/>
</div>
<script>
// 進入畫面 api
// https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
const ob = new IntersectionObserver(targetEvent)
const lazyImgAry = document.querySelectorAll('.lazy-img')
function targetEvent(enterTarget, ob) {
console.log('target')
console.log(enterTarget)
enterTarget.forEach((targetImg) => {
// 是否進入畫面
if (targetImg.isIntersecting) {
const targetEl = targetImg.target
// attribute `data-src`內容 寫入 img src
targetEl.src = targetEl.dataset.src
targetEl.removeAttribute('data-src')
// 移除監聽
ob.unobserve(targetEl)
}
})
}
lazyImgAry.forEach((imgItem) => {
// 把元素加入監聽
ob.observe(imgItem)
})
</script>
</body>
</html>