實(shí)現(xiàn)懶加載
原文合集地址如下,有需要的朋友可以關(guān)注
[本文地址](https://mp.weixin.qq.com/s?__biz=MzI5MjY4OTQ2Nw==&mid=2247484202&idx=1&sn=24ab0996dd892dce23706bfec90486f3&chksm=ec7cc07edb0b4968967ac62a5478eb1544b274dff1d195178dbc7dfa2d6dfc5f0506c354a111#rd)
[合集地址](https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzI5MjY4OTQ2Nw==&action=getalbum&album_id=2968599106275246086&scene=173&from_msgid=2247484202&from_itemidx=1&count=3&nolastread=1#wechat_redirect)
# 什么是懶加載
只在數(shù)據(jù)或內(nèi)容即將進(jìn)入視口或即將需要的時候才加載。 實(shí)現(xiàn)懶加載的好處有:
1.? 提高頁面加載速度和響應(yīng)速度。只加載當(dāng)前用戶需要或?qū)⒁獮g覽到的數(shù)據(jù),避免一次性加載大量不必要的數(shù)據(jù)。
1.? 節(jié)省用戶流量。只加載用戶瀏覽到的數(shù)據(jù),避免加載用戶未瀏覽的數(shù)據(jù),特別是對于移動端用戶來說可以節(jié)省流量。
1.? 優(yōu)化用戶體驗(yàn)。避免一次性加載大量數(shù)據(jù)導(dǎo)致頁面卡頓,appear突然出現(xiàn),樣式渲染跳躍等影響用戶體驗(yàn)的問題。 實(shí)現(xiàn)懶加載的弊端有:
1.? 首屏加載會較慢,而一些關(guān)鍵數(shù)據(jù)又需要首屏加載,需要權(quán)衡。
1.? 需要監(jiān)聽瀏覽器事件并判斷元素是否進(jìn)入視口,稍微增加了開發(fā)難度。
1.? 如果數(shù)據(jù)較多,需要加載的內(nèi)容較長,用戶體驗(yàn)還是會受到影響。懶加載并非銀彈,還需要結(jié)合其他優(yōu)化手段。
1.? 不利于 SEO。搜索引擎爬蟲抓取不到實(shí)際內(nèi)容,抓取到的可能是 loading 占位圖等,影響網(wǎng)頁Indexed和排名。 所以,懶加載是一種非常 useful 的技術(shù),可以極大提高用戶體驗(yàn)和網(wǎng)頁性能,但也有一定的弊端,需要權(quán)衡選擇。一般來說,對于加載的數(shù)據(jù)較多,頁面性能和流量較為關(guān)注的場景,懶加載是一個不錯的方案。但如果對 SEO 優(yōu)化要求較高,或者加載的數(shù)據(jù)較少,也可以不使用懶加載。
## 實(shí)現(xiàn)圖片懶加載
頁面需要大量展示圖片時可以考慮使用懶加載。實(shí)現(xiàn)步驟如下:
1.? 為圖片添加默認(rèn)的 loading 圖片源和真實(shí)的 src 屬性:
```
<img src="loading.gif" src="real-img.jpg" />
```
2.? 獲取所有圖片元素:
```
const images = document.querySelectorAll('img');
```
3.? 監(jiān)聽頁面滾動事件:
```
window.addEventListener('scroll', loadImages);
```
4.? 定義 loadImages 函數(shù)來加載圖片:
```
function loadImages() {
? for (let i = 0; i < images.length; i++) {
? ? // 獲取圖片源和位置信息
? ? let imgSrc = images[i].dataset.src;
? ? let imgRect = images[i].getBoundingClientRect();
? ??
? ? if (imgRect.top < window.innerHeight && imgRect.left < window.innerWidth
? ? ?&& imgRect.right > 0 && imgRect.bottom > 0) {??
? ? ? // 圖片進(jìn)入視口,加載真實(shí)圖片源
? ? ? images[i].src = imgSrc;??
? ? ? images[i].addEventListener('load', () => {?
? ? ? ? images[i].style.opacity = 1;? // 淡入效果
? ? ? });
? ? }?
? }
}
```
5.? 頁面初始化時調(diào)用一次 loadImages,防止某些圖片已進(jìn)入視口但未加載:
```
loadImages();
```
6.? 為避免加載較大圖片導(dǎo)致頁面卡頓,可以考慮在圖片加載完成后設(shè)置淡入效果:
```
images[i].addEventListener('load', () => {?
? images[i].style.opacity = 1;??
});
```
## 列表懶加載
這里提供一個核心代碼,根據(jù)自己項(xiàng)目加入即可
```
// 比如使用我有這樣一個
// 定義頁碼和加載條數(shù)
const pageSize = 10;? ?
let currentPage = 1;??
// list 代表擁有滾動條的元素, 看你代碼如何定義,可以是網(wǎng)頁窗口 window、div元素、ul列表等等
// 需要先獲取list 元素,再監(jiān)聽列表中的元素進(jìn)入視口事件,判斷元素位置并加載數(shù)據(jù)
list.addEventListener('scroll', () => {
? Array.from(list.children).forEach(elem => {
? ? let top = elem.offsetTop;
? ? let height = elem.clientHeight;
? ? if (top > 0 && top < window.innerHeight) {??
? ? ? // 元素進(jìn)入視口,加載數(shù)據(jù)
? ? ? fetchData(currentPage);
? ? ? currentPage++;
? ? }
? });
});?
定義 fetchData() 方法根據(jù)頁碼加載數(shù)據(jù),并更新元素內(nèi)容:
function fetchData(page) {
? // 發(fā)起請求,加載第page頁的數(shù)據(jù),此處省略調(diào)用接口的代碼,根據(jù)自己代碼結(jié)構(gòu)加入即可
? ...
? ...
? // 更新列表中符合頁碼的元素內(nèi)容
? Array.from(list.children).forEach(elem => {
? ? if (elem.dataset.page === page) {??
? ? ? elem.innerHTML = ... // 加載的數(shù)據(jù)內(nèi)容
? ? }
? });
}?
// 初始化加載第一頁數(shù)據(jù),并為每個列表元素添加 data-page 屬性:
fetchData(1);
Array.from(list.children).forEach((elem, index) => {
? elem.dataset.page = index % 10 + 1;? // 每10個元素為一頁
});
```
## 列表滾動加載
如果是加載列表數(shù)據(jù)的話,這里提供一個實(shí)現(xiàn)滾動加載列表數(shù)據(jù)的代碼
```
// 1. 定義頁面大小、每頁加載條數(shù)和當(dāng)前頁碼:
const pageSize = 10;? ? ?// 每頁10條數(shù)據(jù)?
const listHeight = 400;? // 比如列表容器高度400px?
let currentPage = 1;? ? ?// 當(dāng)前頁碼
let scrollTop = 0;? // 上一次滾動條位置?
//? 2. 綁定滾動事件,判斷滾動方向并加載數(shù)據(jù):
list.addEventListener('scroll', () => {
? let scrollHeight = list.scrollHeight;? // 滾動內(nèi)容高度
? let clientHeight = list.clientHeight;? // 視口高度
? let scrollDirection = scrollTop - list.scrollTop;?
? // 向下滾動
? if (scrollDirection > 0 && scrollHeight - clientHeight - list.scrollTop <= pageSize * 3) {
? ? // 滾動到底部,加載下一頁
? ? currentPage++;
? ? fetchData(currentPage);?
? }?
??
? // 向上滾動?
? if (scrollDirection < 0 && list.scrollTop <= pageSize * 3) {
? ? // 滾動到頂部,加載上一頁
? ? currentPage--;?
? ? fetchData(currentPage);
? }
??
? scrollTop = list.scrollTop;? // 更新滾動條位置
});?
// 定義 fetchData() 方法,根據(jù)頁碼加載數(shù)據(jù):
function fetchData(page) {
? // 發(fā)起請求,加載第page頁的數(shù)據(jù)
? ...
??
? // 將新加載的數(shù)據(jù)添加到列表尾部
? list.append(...);?
}
// 初始化獲取第一頁數(shù)據(jù)
fetchData(1)
```