一開始將img標籤的src設置爲一張默認圖片,將真實的圖片地址放在data-src上,監聽滾動事件,當圖片進入可視區域時,寫入src真實的圖片地址。
對於這樣一個頁面,圖片即將進入頁面的條件是:圖片距離整個網頁頂部的距離 < 瀏覽器可視區域的高度 + 滾動條滾動的距離。那麼問題就能夠分解成三個小點:css
能夠經過下面這個方法獲取某個元素到網頁頂部的距離:html
function getElementTop (element) { let actualTop = element.offsetTop; let parent = element.offsetParent; while (parent !== null) { actualTop += parent.offsetTop; parent = parent.offsetParent; } return actualTop; }
代碼分析:offsetTop
表示的是元素距離父元素左上角頂點的高度,offsetParent
則表示元素的父元素。經過不斷遍歷累加高度,就能夠獲得元素距離網頁頂部的距離。瀏覽器
即window.innerHeight
閉包
即document.documentElement.scrollTop
app
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代碼以下:ui
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
表示在滾動條滾動時觸發調用lazyLoad方法;spa
在lazyLoad方法中,先經過document.querySelectorAll('img');
找到全部的Image(這裏只是爲了簡化示例,實際場景中能夠經過在須要懶加載的圖片上添加統一的類名,而後經過querySelectorAll('.類名')
來獲取須要懶加載的圖片),依次判斷是否進入了可視區域內。若是進入了可視區域則作img標籤的src的替換。
須要手動調用一次lazyLoad
方法,在頁面剛load的時候將已經在視窗內的圖片加載出來。
所謂的函數節流就是當事件觸發的頻率很高時,並非每次都須要去調用相對應的處理函數,以此來提升性能。好比這裏的滾動事件,假設咱們但願至少間隔200ms才調用一次處理函數,那麼能夠新增一個方法
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)
。這個函數在事件觸發時,先去判斷本次觸發的時間和上次觸發的時間的間隔,若是大於delay, 則運行處理函數。
函數用到了閉包的原理來保存last
這個變量,對於閉包簡單的解釋一下就是throttle
這個函數在調用結束後,原本應該銷燬掉其內部的last
變量,可是因爲返回的是一個函數,返回的函數內引用了last
這個變量,所以last
被一直保存在了內存中。
throttle
這個方法還有不少能夠優化的地方,不在這裏展開了。主題是懶加載嘛,後面有空了專門寫一篇函數節流方法的文章。