利用原生JS實(shí)現(xiàn)懶加載lazyLoad的三種方法總結(jié)
前言
首先我們先搭建好頁(yè)面如下:

<style>
* {
padding: 0%;
margin: 0%;
}
.contain img {
width: 600px;
height: 400px;
}
ul {
list-style: none;
}
li {
display: inline-block;
}
</style>
<div class="contain">
<ul>
<li><img data-src="./images/iu.jpg" src='./images/lazy.png' alt=""></li>
<li><img data-src="./images/iu1.jpg" src='./images/lazy.png' alt=""></li>
<li><img data-src="./images/iu2.png" src='./images/lazy.png' alt=""></li>
<li><img data-src="./images/iu3.jpg" src='./images/lazy.png' alt=""></li>
<li><img data-src="./images/iu4.jpg" src='./images/lazy.png' alt=""></li>
<li><img data-src="./images/iu5.jpg" src='./images/lazy.png' alt=""></li>
<li><img data-src="./images/iu6.jpg" src='./images/lazy.png' alt=""></li>
<li><img data-src="./images/iu7.jpg" src='./images/lazy.png' alt=""></li>
<li><img data-src="./images/iu8.jpg" src='./images/lazy.png' alt=""></li>
<li><img data-src="./images/iu9.jpg" src='./images/lazy.png' alt=""></li>
<li><img data-src="./images/iu10.jpg" src='./images/lazy.png' alt=""></li>
<li><img data-src="./images/zzf_01.jpg" src='./images/lazy.png' alt=""></li>
</ul>
</div
>

我們知道,圖片懶加載是在滾動(dòng)條向下滾動(dòng)時(shí),才判斷圖片是否到達(dá)可視區(qū)域
于是我們需要在滾動(dòng)監(jiān)聽時(shí)判斷圖片是否即將顯示,所以我們需要將圖片的真實(shí)地址先隱藏起來(lái),即采用自定義屬性 data-src 保存圖片的真實(shí)地址,當(dāng)滾動(dòng)條滾動(dòng)到圖片能夠看到時(shí)再加載真實(shí)的地址.
下面我們來(lái)看第一個(gè)方法
Method 1: 高度對(duì)比
這里我們采用 (元素距頂部的高度 - 頁(yè)面被卷去的高度 <= 瀏覽器可視區(qū)的高度) 來(lái)判斷是否符合我們想要的條件.這里我們需要實(shí)時(shí)監(jiān)聽頁(yè)面滾動(dòng)時(shí) 圖片的高度變化
/**
* 方法一
* 高度對(duì)比
*/
let imgs = [...document.querySelectorAll('img')]; // 先獲取所有的圖片
window.addEventListener('scroll', function () {
})
添加完事件后再繼續(xù)判斷 圖片是否達(dá)到要求,即
/**
* 方法一
* 高度對(duì)比
*/
let imgs = [...document.querySelectorAll('img')]; // 先獲取所有的圖片
window.addEventListener('scroll', function () {
lazyLoad(imgs)
})
function lazyLoad(imgs) {
for (var i = 0; i < imgs.length; i++) {
var height = imgs[i].offsetTop; // 圖片的距頂部的高度
var wheight = window.innerHeight; // 瀏覽器可視區(qū)的高度
var sheight = document.documentElement.scrollTop; // 頁(yè)面被卷去的高度
if (height - sheight <= wheight) { // 判斷圖片是否將要出現(xiàn)
imgs[i].src = imgs[i].dataset.src; // 出現(xiàn)后將自定義地址轉(zhuǎn)為真實(shí)地址
}
}
}
看起來(lái)還挺簡(jiǎn)單的對(duì)吧? 不過(guò)我們還有更簡(jiǎn)單的方法,如下:
Method 2: 使用getBoundingClientRect() 的API
先附上MDN 對(duì)getBoundingClientRect() 的解釋getBoundingClientRect()

我們可以通過(guò) getBoundingClientRect().top來(lái)獲取元素距視口頂部的距離,于是我們就可以比較getBoundingClientRect().top 和 window.innerHeight 的值的關(guān)系來(lái)實(shí)現(xiàn)懶加載的效果
這里使用了getAttribute() 和setAttribute() 屬性
/**
* 方法二
* @params getBoundingClientRect()
* 可視區(qū)API
*/
let imgs = [...document.querySelectorAll('img')];
window.addEventListener('scroll', function () {
imgs.forEach(img => {
//這里其實(shí)和Method1的思想一樣,不過(guò)就是簡(jiǎn)潔了一些
if (img.getBoundingClientRect().top < window.innerHeight) {
let dataSrc = img.getAttribute(' data-src'); // 獲取 data-src 真實(shí)的地址
img.setAttribute('src', dataSrc); // 將 真實(shí)的地址 替換為 src屬性
console.log(img.src);
}
})
})
Method 3: 采用最新的 IntersectionObserver 構(gòu)造函數(shù)
看過(guò)上面兩種方法,那你是否覺得懶加載還挺簡(jiǎn)單的對(duì)吧?
沒錯(cuò),我們寫的代碼很少,看起來(lái)很簡(jiǎn)單,但是我們忽略了一個(gè)重要的問題:
圖片替換為真實(shí)的地址之后,如果我們反復(fù)的拉動(dòng)滾動(dòng)條,會(huì)一直觸發(fā) if()條件,
所以我在 Method2 方法里給了一個(gè) console.log(img.src);
目的就是為了讓你看到當(dāng)有人持續(xù)不斷的拉動(dòng)滾動(dòng)條,會(huì)一直打印 console.log(img.src);
那我們?cè)趺慈プ寛D片真實(shí)地址加載完之后,不再觸發(fā)對(duì)它的頻繁操作呢?或者說(shuō)怎么優(yōu)化游覽器的性能呢?
好巧不巧,現(xiàn)在有了一個(gè)新增的構(gòu)造函數(shù),來(lái)解決我們的頻繁觸發(fā)條件語(yǔ)句的問題.
這個(gè)構(gòu)造函數(shù)就是 IntersectionObserver
根據(jù) MDN 上的解釋
- IntersectionObserver()構(gòu)造器創(chuàng)建并返回一個(gè)IntersectionObserver對(duì)象。 如果指定rootMargin則會(huì)檢查其是否符合語(yǔ)法規(guī)定,檢查閾值以確保全部在0.0到1.0之間,并且閾值列表會(huì)按升序排列。如果閾值列表為空,則默認(rèn)為一個(gè)[0.0]的數(shù)組。
- callback當(dāng)元素可見比例超過(guò)指定閾值后,會(huì)調(diào)用一個(gè)回調(diào)函數(shù),此回調(diào)函數(shù)接受兩個(gè)參數(shù):
entries一個(gè)IntersectionObserverEntry對(duì)象的數(shù)組,每個(gè)被觸發(fā)的閾值,都或多或少與指定閾值有偏差。
observer被調(diào)用的IntersectionObserver實(shí)例。
這里我們只使用第一個(gè)參數(shù) callback 這個(gè)回調(diào)函數(shù)
window.addEventListener('scroll', function () {
// 首先我們先實(shí)例化這個(gè)構(gòu)造函數(shù)
const observe = new IntersectionObserver(callback);
// 然后寫我們需要處理業(yè)務(wù)的回調(diào)函數(shù) callback
const callback = entries => {
console.log(entries); //我們先打印一下 entries 看看有什么用
// 如下圖
};
}

window.addEventListener('scroll', function () {
const observe = new IntersectionObserver(callback);
// 然后寫我們需要處理業(yè)務(wù)的回調(diào)函數(shù) callback
const callback = entries => {
// 我們發(fā)現(xiàn)它是個(gè)數(shù)組,于是
entries.forEach(ele => {
console.log(ele); // 我們?cè)俅蛴∫幌略?看看元素里面有什么
// 如下圖
})
};
}

我們找到了 isIntersecting: false 這個(gè)屬性,這個(gè)意思是 是否交叉,根據(jù)構(gòu)造函數(shù)的意義我們得知,交叉可以理解為是否被觀察到
如果被觀察到, 那我們就讓他的真實(shí)地址替換為 它的 src 屬性 ,并且取消對(duì)它的觀察
/**
* 方法三
* @params new IntersectionObserver(callback[,options])
* 觀察-->構(gòu)造函數(shù)
*/
window.addEventListener('scroll', function () {
let imgs = [...document.querySelectorAll('.img')]
const callback = entries => { // entries 是觀察的元素?cái)?shù)組
entries.forEach(ele => {
if (ele.isIntersecting) { // isIntersecting 是否被觀察到
const data_src = ele.target.getAttribute('data-src'); //這里基本和 Method1/Method2一樣
ele.target.setAttribute('src', data_src); // ele.target 是目標(biāo)元素
observe.unobserve(ele.target) // 真實(shí)地址替換后 取消對(duì)它的觀察
}
})
};
const observe = new IntersectionObserver(callback); // 實(shí)例化 IntersectionObserver
imgs.forEach(image => {
observe.observe(image) // observe : 被調(diào)用的IntersectionObserver實(shí)例。給每個(gè)圖片添加觀察實(shí)例
})
}
這樣處理,我們就可以不再頻繁的去觸發(fā) if() 條件語(yǔ)句
因?yàn)樵趫D片替換了真實(shí)地址后,我取消了對(duì)當(dāng)前圖片的觀察,于是,當(dāng)前圖片已經(jīng)沒有事件再被觸發(fā),所以這樣對(duì)瀏覽器的性能進(jìn)行了極大的優(yōu)化
總結(jié)
到此這篇關(guān)于利用原生JS實(shí)現(xiàn)懶加載lazyLoad的三種方法的文章就介紹到這了,更多相關(guān)JS實(shí)現(xiàn)懶加載lazyLoad內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
解決微信小程序云開發(fā)中獲取數(shù)據(jù)庫(kù)的內(nèi)容為空的方法
這篇文章主要介紹了解決微信小程序云開發(fā)中獲取數(shù)據(jù)庫(kù)的內(nèi)容為空的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-05-05
uniapp退出關(guān)閉當(dāng)前小程序或APP的簡(jiǎn)單實(shí)現(xiàn)
最近通過(guò)Uniapp開發(fā)APP又一個(gè)非常實(shí)用的功能,這篇文章主要給大家介紹了關(guān)于uniapp退出關(guān)閉當(dāng)前小程序或APP的簡(jiǎn)單實(shí)現(xiàn),文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-12-12
Firefox中autocomplete="off" 設(shè)置不起作用Bug的解決方法
在實(shí)現(xiàn)補(bǔ)全提示功能時(shí)(Suggest),都會(huì)給輸入框(Input)元素添加autocomplete屬性,且值設(shè)為off。2011-03-03
p5.js臨摹動(dòng)態(tài)圖形實(shí)現(xiàn)方法詳解
這篇文章主要為大家詳細(xì)介紹了p5.js臨摹動(dòng)態(tài)圖形的實(shí)現(xiàn)方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-10-10
JavaScript setTimeout和setInterval的使用方法 說(shuō)明
兩個(gè)函數(shù)都是可以用來(lái)實(shí)現(xiàn)一段時(shí)間后執(zhí)行一段javascript代碼的效果。兩個(gè)函數(shù)都有兩個(gè)參數(shù),前面的都是執(zhí)行表達(dá)式,后面的是隔的秒數(shù)。2010-03-03
JavaScript設(shè)計(jì)模式之觀察者模式(發(fā)布者-訂閱者模式)
這篇文章主要介紹了JavaScript設(shè)計(jì)模式之觀察者模式(發(fā)布者-訂閱者模式),本文詳細(xì)的講解了JavaScript中的觀察者模式,需要的朋友可以參考下2014-09-09

