原理
一開始將img標簽的src設(shè)置為一張默認圖片局冰,將真實的圖片地址放在data-src上测蘑,監(jiān)聽滾動事件,當圖片進入可視區(qū)域時康二,寫入src真實的圖片地址帮寻。
如何判斷圖片進入了可視區(qū)域?
對于這樣一個頁面赠摇,圖片即將進入頁面的條件是:圖片距離整個網(wǎng)頁頂部的距離 < 瀏覽器可視區(qū)域的高度 + 滾動條滾動的距離固逗。那么問題就可以分解成三個小點:
①圖片距離整個網(wǎng)頁頂部的距離;
可以通過下面這個方法獲取某個元素到網(wǎng)頁頂部的距離:
function getElementTop (element) {
let actualTop = element.offsetTop;
let parent = element.offsetParent;
while (parent !== null) {
actualTop += parent.offsetTop;
parent = parent.offsetParent;
}
return actualTop;
}
代碼分析:
offsetTop
表示的是元素距離父元素左上角頂點的高度藕帜,offsetParent
則表示元素的父元素烫罩。通過不斷遍歷累加高度,就可以得到元素距離網(wǎng)頁頂部的距離洽故。
②瀏覽器可視區(qū)域的高度贝攒;
即window.innerHeight
③滾動條滾動的距離。
即document.documentElement.scrollTop
懶加載如何實現(xiàn)时甚?
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">
<title>Document</title>
<link rel="stylesheet" href="./lazyLoad.css">
</head>
<body>
<div class="wrapper">
<img src="./default.jpg" data-src="./dog0.jpg">
<img src="./default.jpg" data-src="./dog1.jpg">
<img src="./default.jpg" data-src="./dog2.jpg">
<img src="./default.jpg" data-src="./dog3.jpg">
<img src="./default.jpg" data-src="./dog4.jpg">
<img src="./default.jpg" data-src="./dog5.jpg">
<img src="./default.jpg" data-src="./dog6.jpg">
</div>
<script src="./lazyLoad.js"></script>
</body>
</html>
這里只需要注意到開始時img標簽的src屬性放的是默認的圖片隘弊,真正的圖片地址放在了data-src中
css代碼如下:
.wrapper {
text-align: center;
}
img {
display: block;
margin: 10px auto;
}
js代碼如下:
function lazyLoad () {
let images = document.querySelectorAll('img');
for(let i = 0; i < images.length; i++) {
let image = images[i];
if (getElementTop(image) <= window.innerHeight + document.documentElement.scrollTop) {
image.src = image.getAttribute('data-src');
}
}
}
function getElementTop (element) {
let actualTop = element.offsetTop;
let parent = element.offsetParent;
while (parent !== null) {
actualTop += parent.offsetTop;
parent = parent.offsetParent;
}
return actualTop;
}
lazyLoad();
window.onscroll =lazyLoad荒适;
代碼分析:
window.onscroll = lazyload
表示在滾動條滾動時觸發(fā)調(diào)用lazyLoad方法梨熙;
在lazyLoad方法中,先通過document.querySelectorAll('img');
找到所有的Image(這里只是為了簡化示例刀诬,實際場景中可以通過在需要懶加載的圖片上添加統(tǒng)一的類名咽扇,然后通過querySelectorAll('.類名')
來獲取需要懶加載的圖片),依次判斷是否進入了可視區(qū)域內(nèi)。如果進入了可視區(qū)域則做img標簽的src的替換。
需要手動調(diào)用一次lazyLoad
方法质欲,在頁面剛load的時候?qū)⒁呀?jīng)在視窗內(nèi)的圖片加載出來树埠。
函數(shù)節(jié)流
所謂的函數(shù)節(jié)流就是當事件觸發(fā)的頻率很高時,并不是每次都需要去調(diào)用相對應(yīng)的處理函數(shù)嘶伟,以此來提高性能怎憋。比如這里的滾動事件,假設(shè)我們希望至少間隔200ms才釣魚那個一次處理函數(shù)九昧,那么可以新增一個方法
function throttle (delay, action) {
let last = 0;
return function () {
let now = new Date();
if (now - last > delay) {
action();
last = now;
}
}
}
然后將window.onscroll =lazyLoad盛霎;
改成window.onscroll = throttle(200, lazyLoad)
。這個函數(shù)在事件觸發(fā)時耽装,先去判斷本次觸發(fā)的時間和上次觸發(fā)的時間的間隔,如果大于delay期揪, 則運行處理函數(shù)掉奄。
函數(shù)用到了閉包的原理來保存last
這個變量,對于閉包簡單的解釋一下就是throttle
這個函數(shù)在調(diào)用結(jié)束后凤薛,本來應(yīng)該銷毀掉其內(nèi)部的last
變量姓建,但是由于返回的是一個函數(shù),返回的函數(shù)內(nèi)引用了last
這個變量缤苫,因此last
被一直保存在了內(nèi)存中速兔。
throttle
這個方法還有很多可以優(yōu)化的地方,不在這里展開了活玲。主題是懶加載嘛涣狗,后面有空了專門寫一篇函數(shù)節(jié)流方法的文章。