延遲加載也稱為惰性加載,即在長網頁中延遲加載圖像。用戶滾動到它們之前,視口外的圖像不會加載。這與圖像預加載相反,在長網頁上使用延遲加載將使網頁加載更快。在某些情況下,它還可以幫助減少服務器負載。
那么延遲加載有什么好處:
1、提升用戶的體驗,避免出現卡頓現象。
2、有選擇性地請求圖片,減少服務器的壓力和流量,減小瀏覽器的負擔。
實現方式:
1、首先將頁面上的圖片的 src 屬性設為 loading.gif,而圖片的真實路徑則設置在 data-src 屬性中,頁面滾動的時候計算圖片的位置與滾動的位置,當圖片出現在瀏覽器視口內時,將圖片的 src 屬性設置為 data-src 的值,這樣,就可以實現延遲加載
<!DOCTYPE html> <html > <head> <meta charset="UTF-8"> <title>Lazyload 1</title> <style> img { display: block; margin-bottom: 50px; height: 200px; } </style> </head> <body> <img src="images/loading.gif" data-src="images/1.png"> <img src="images/loading.gif" data-src="images/2.png"> <img src="images/loading.gif" data-src="images/3.png"> <img src="images/loading.gif" data-src="images/4.png"> <img src="images/loading.gif" data-src="images/5.png"> <img src="images/loading.gif" data-src="images/6.png"> <img src="images/loading.gif" data-src="images/7.png"> <img src="images/loading.gif" data-src="images/8.png"> <img src="images/loading.gif" data-src="images/9.png"> <img src="images/loading.gif" data-src="images/10.png"> <img src="images/loading.gif" data-src="images/11.png"> <img src="images/loading.gif" data-src="images/12.png"> <script> function lazyload() { var images = document.getElementsByTagName('img'); var len = images.length; var n = 0; //存儲圖片加載到的位置,避免每次都從第一張圖片開始遍歷 return function() { var seeHeight = document.documentElement.clientHeight; var scrollTop = document.documentElement.scrollTop || document.body.scrollTop; for(var i = n; i < len; i++) { if(images[i].offsetTop < seeHeight + scrollTop) { if(images[i].getAttribute('src') === 'images/loading.gif') { images[i].src = images[i].getAttribute('data-src'); } n = n + 1; } } } } var loadImages = lazyload(); loadImages(); //初始化首頁的頁面圖片 window.addEventListener('scroll', loadImages, false); </script> </body> </html>
不斷滑動頁面時,圖片延遲加載。 image 的 offsetTop 與 seeHeight + scrollTop 的大小,當小於時則說明圖片已經出現過在視口中,這時候繼續判斷圖片是否已經替換過,如果沒有替換過,則進行替換。
上面的代碼是沒什么問題,但是性能偏差。如果直接將函數綁定在 scroll 事件上,當頁面滾動時,函數會被高頻觸發,這非常影響瀏覽器的性能。我粗略地估計一下,當簡單地滾動一下頁面,函數至少觸發了十來次,這顯然是十分沒必要的。
2、所以在做事件綁定的時候,可以對 lazyload 函數進行函數節流(throttle)與函數去抖(debounce)處理。
Debounce:一部電梯停在某一個樓層,當有一個人進來后,20秒后自動關門,這20秒的等待期間,又一個人按了電梯進來,這20秒又重新計算,直到電梯關門那一刻才算是響應了事件。
Throttle:好比一台自動的飲料機,按拿鐵按鈕,在出飲料的過程中,不管按多少這個按鈕,都不會連續出飲料,中間按鈕的響應會被忽略,必須要等這一杯的容量全部出完之后,再按拿鐵按鈕才會出下一杯。

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Lazyload 2</title> <style> img { display: block; margin-bottom: 50px; height: 200px; } </style> </head> <body> <img src="images/loading.gif" data-src="images/1.png"> <img src="images/loading.gif" data-src="images/2.png"> <img src="images/loading.gif" data-src="images/3.png"> <img src="images/loading.gif" data-src="images/4.png"> <img src="images/loading.gif" data-src="images/5.png"> <img src="images/loading.gif" data-src="images/6.png"> <img src="images/loading.gif" data-src="images/7.png"> <img src="images/loading.gif" data-src="images/8.png"> <img src="images/loading.gif" data-src="images/9.png"> <img src="images/loading.gif" data-src="images/10.png"> <img src="images/loading.gif" data-src="images/11.png"> <img src="images/loading.gif" data-src="images/12.png"> <script> function throttle(fn, delay, atleast) { var timeout = null, startTime = new Date(); return function() { var curTime = new Date(); clearTimeout(timeout); if(curTime - startTime >= atleast) { fn(); startTime = curTime; }else { timeout = setTimeout(fn, delay); } } } function lazyload() { var images = document.getElementsByTagName('img'); var len = images.length; var n = 0; //存儲圖片加載到的位置,避免每次都從第一張圖片開始遍歷 return function() { var seeHeight = document.documentElement.clientHeight; var scrollTop = document.documentElement.scrollTop || document.body.scrollTop; for(var i = n; i < len; i++) { if(images[i].offsetTop < seeHeight + scrollTop) { if(images[i].getAttribute('src') === 'images/loading.gif') { images[i].src = images[i].getAttribute('data-src'); } n = n + 1; } } } } var loadImages = lazyload(); loadImages(); //初始化首頁的頁面圖片 window.addEventListener('scroll', throttle(loadImages, 500, 1000), false); </script> </body> </html>
設置了 500ms 的延遲,和 1000ms 的間隔,當超過 1000ms 未觸發該函數,則立即執行該函數,不然則延遲 500ms 執行該函數。
預加載圖片是提高用戶體驗的一個很好方法。圖片預先加載到瀏覽器中,訪問者便可順利地在你的網站上沖浪,並享受到極快的加載速度。這對圖片畫廊及圖片占據很大比例的網站來說十分有利,它保證了圖片快速、無縫地發布,也可幫助用戶在瀏覽你網站內容時獲得更好的用戶體驗。
1、用CSS和JavaScript實現預加載
#preload-01 { background: url(-01.png) no-repeat -9999px -9999px; } #preload-02 { background: url(-02.png) no-repeat -9999px -9999px; } #preload-03 { background: url(-03.png) no-repeat -9999px -9999px; }
將這三個ID選擇器應用到(X)HTML元素中,我們便可通過CSS的background屬性將圖片預加載到屏幕外的背景上。只要這些圖片的路徑保持不變,當它們在Web頁面的其他地方被調用時,瀏覽器就會在渲染過程中使用預加載(緩存)的圖片。簡單、高效,不需要任何JavaScript。
該方法雖然高效,但仍有改進余地。使用該法加載的圖片會同頁面的其他內容一起加載,增加了頁面的整體加載時間。為了解決這個問題,我們增加了一些JavaScript代碼,來推遲預加載的時間,直到頁面加載完畢。代碼如下:
function preloader() { if (document.getElementById) { document.getElementById("preload-01").style.background = "url() no-repeat -9999px -9999px"; document.getElementById("preload-02").style.background = "url() no-repeat -9999px -9999px"; document.getElementById("preload-03").style.background = "url() no-repeat -9999px -9999px"; } } function addLoadEvent(func) { var oldonload = window.onload; //獲得window.onload的內容 if (typeof window.onload != 'function') { //判斷windown.onload是否為函數。如果不是函數,則執行自己的函數,如果是函數,則先執行已經賦值的函數,再執行自己的函數 window.onload = func; } else { window.onload = function() { if (oldonload) { oldonload(); } func(); } } } addLoadEvent(preloader);
2、純JavaScript實現,與Css實現相比,會減少時間
function preloader() { if (document.images) { var img1 = new Image(); var img2 = new Image(); var img3 = new Image(); img1.src = ";; img2.src = ";; img3.src = ";; } } function addLoadEvent(func) { var oldonload = window.onload; if (typeof window.onload != 'function') { window.onload = func; } else { window.onload = function() { if (oldonload) { oldonload(); } func(); } } } addLoadEvent(preloader);
3、使用Ajax實現預加載
上面所給出的方法似乎不夠酷,那現在來看一個使用Ajax實現圖片預加載的方法。該方法利用DOM,不僅僅預加載圖片,還會預加載CSS、JavaScript等相關的東西。使用Ajax,比直接使用JavaScript,優越之處在於JavaScript和CSS的加載不會影響到當前頁面。該方法簡潔、高效。
window.onload = function() { setTimeout(function() { // XHR to request a JS and a CSS var xhr = new XMLHttpRequest(); xhr.open('GET', ';); xhr.send(''); xhr = new XMLHttpRequest(); xhr.open('GET', ';); xhr.send(''); // preload image new Image().src = ";; }, 1000); };
上面代碼預加載了“preload.js”、“preload.css”和“preload.png”。1000毫秒的超時是為了防止腳本掛起,而導致正常頁面出現功能問題。
window.onload = function() { setTimeout(function() { // reference to <head> var head = document.getElementsByTagName('head')[0]; // a new CSS var css = document.createElement('link'); css.type = "text/css"; css.rel = "stylesheet"; css.href = ";; // a new JS var js = document.createElement("script"); js.type = "text/javascript"; js.src = ";; // preload JS and CSS head.appendChild(css); head.appendChild(js); // preload image new Image().src = ";; }, 1000); };