圖片懶加載的核心實現方法有三種:1. 使用 data-src 屬性 + 滾動監聽;2. 使用 intersection observer api;3. 結合 requestanimationframe 優化滾動監聽。此外,還可通過設置 offset 或 rootmargin 實現預加載,選擇合適的占位圖優化體驗,并通過 onerror 處理加載失敗問題,測試時可通過開發者工具的 network 面板觀察圖片是否按需加載。
圖片懶加載,簡單來說,就是讓頁面上的圖片不是一次性全部加載,而是等到它們進入用戶視口(或者即將進入)時才加載。這樣可以顯著提高頁面初始加載速度,優化用戶體驗,特別是對于圖片較多的頁面。
解決方案
實現懶加載的核心在于:監聽圖片的 src 屬性,當圖片進入視口時,才將真實的圖片地址賦給 src。
-
基礎實現:data-src 屬性 + 滾動監聽
這是最常見的做法。首先,將圖片的真實地址放到 data-src 屬性中,src 屬性留空或者放一張占位圖。
@@##@@ @@##@@ @@##@@
然后,通過 JavaScript 監聽滾動事件,判斷圖片是否進入視口。
const images = document.querySelectorAll('img[data-src]'); function loadImage(img) { img.src = img.dataset.src; img.removeAttribute('data-src'); // Optional: Remove data-src after loading } function isElementInViewport(el) { const rect = el.getBoundingClientRect(); return ( rect.top >= 0 && rect.left >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && rect.right <= (window.innerWidth || document.documentElement.clientWidth) ); } function checkImages() { images.forEach(img => { if (isElementInViewport(img)) { loadImage(img); } }); } document.addEventListener('scroll', checkImages); window.addEventListener('resize', checkImages); // Also check on resize checkImages(); // Initial check
這種方法簡單直接,但缺點是需要頻繁監聽滾動事件,可能會影響性能。
-
使用 Intersection Observer API
Intersection Observer API 是一種更高效的方式來監聽元素是否進入視口,它基于瀏覽器的優化,避免了頻繁的滾動監聽。
const images = document.querySelectorAll('img[data-src]'); const observer = new IntersectionObserver((entries, observer) => { entries.forEach(entry => { if (entry.isIntersecting) { const img = entry.target; loadImage(img); observer.unobserve(img); // Stop observing after loading } }); }); images.forEach(img => { observer.observe(img); }); function loadImage(img) { img.src = img.dataset.src; img.removeAttribute('data-src'); }
Intersection Observer API 性能更好,推薦使用。
-
結合 requestAnimationFrame 優化滾動監聽
如果選擇使用滾動監聽,可以結合 requestAnimationFrame 來降低滾動事件的處理頻率,提高性能。
let ticking = false; document.addEventListener('scroll', function(e) { if (!ticking) { window.requestAnimationFrame(function() { checkImages(); ticking = false; }); ticking = true; } });
-
預加載機制
有時候,我們希望圖片在進入視口 之前 就開始加載,這樣可以避免用戶看到圖片加載過程。 可以在 isElementInViewport 函數中增加一個 offset 值。
function isElementInViewport(el, offset = 100) { const rect = el.getBoundingClientRect(); return ( rect.top >= -offset && rect.left >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) + offset && rect.right <= (window.innerWidth || document.documentElement.clientWidth) ); }
或者,使用 Intersection Observer API 的 rootMargin 選項。
const observer = new IntersectionObserver((entries, observer) => { ... }, { rootMargin: '100px 0px' // Top and bottom margins });
rootMargin 可以控制觸發 Intersection Observer 的邊界。
如何選擇合適的占位圖?
選擇占位圖需要考慮以下幾個因素:
- 大小: 占位圖應該盡可能小,避免增加初始加載時間。可以使用純色背景或者矢量圖。
- 尺寸: 占位圖的尺寸應該和真實圖片的尺寸接近,避免頁面布局跳動。
- 風格: 占位圖的風格應該和頁面整體風格一致,避免突兀感。
- 顏色: 可以使用圖片的平均顏色作為占位圖的顏色,或者使用模糊處理后的圖片作為占位圖。
一些常用的占位圖方案包括:
- 純色背景: 使用和圖片主題顏色相近的純色背景。
- 矢量圖: 使用簡單的矢量圖形作為占位圖。
- LQIP (Low Quality Image Placeholder): 使用極低質量的圖片作為占位圖。
- SQIP (SVG-Based Image Placeholder): 使用 SVG 版本的圖片作為占位圖。
懶加載圖片加載失敗了怎么辦?
圖片懶加載過程中,可能會因為網絡問題或者其他原因導致圖片加載失敗。為了提高用戶體驗,需要處理圖片加載失敗的情況。
-
顯示默認圖片: 當圖片加載失敗時,顯示一張默認圖片。可以使用 onerror 事件來監聽圖片加載失敗。
@@##@@
-
重試加載: 可以嘗試重新加載圖片。可以使用 setTimeout 函數來延遲一段時間后重新加載。
img.onerror = function() { setTimeout(() => { img.src = img.dataset.src; }, 3000); // Retry after 3 seconds };
-
錯誤提示: 可以顯示錯誤提示信息,告訴用戶圖片加載失敗。
如何測試懶加載是否生效?
測試懶加載是否生效,可以按照以下步驟進行:
- 打開開發者工具: 打開瀏覽器的開發者工具(通常按 F12 鍵)。
- 切換到 Network 面板: 在開發者工具中,切換到 Network 面板。
- 禁用緩存: 勾選 “Disable cache” 選項,確保每次加載都是從服務器獲取資源。
- 清空記錄: 點擊 “Clear” 按鈕,清空之前的網絡請求記錄。
- 滾動頁面: 滾動頁面,觀察 Network 面板中的圖片請求。
如果懶加載生效,應該只看到當前視口內的圖片請求,而不是一次性加載所有圖片。可以嘗試快速滾動頁面,觀察圖片是否按需加載。另外,可以觀察圖片的加載時間,如果加載時間過長,需要優化圖片大小或者網絡連接。還可以使用 Lighthouse 等工具來評估頁面性能,并根據評估結果進行優化。