本文主要通過以下幾方面來說明懶加載技術(shù)的原理,個(gè)人前端小菜,有錯(cuò)誤請(qǐng)多多指出
一、什么是圖片滾動(dòng)加載?
通俗的講就是:當(dāng)訪問一個(gè)頁面的時(shí)候,先把img元素或是其他元素的背景圖片路徑替換成一張大小為1*1px圖片的路徑(這樣就只需請(qǐng)求一次),只有當(dāng)圖片出現(xiàn)在瀏覽器的可視區(qū)域內(nèi)時(shí),才設(shè)置圖片正真的路徑,讓圖片顯示出來。這就是圖片懶加載。
二、為什要使用這個(gè)技術(shù)?
比如一個(gè)頁面中有很多圖片,如淘寶、京東首頁等等,如果一上來就發(fā)送這么多請(qǐng)求,頁面加載就會(huì)很漫長,如果js文件都放在了文檔的底部,恰巧頁面的頭部又依賴這個(gè)js文件,那就不好辦了。更為要命的是:一上來就發(fā)送百八十個(gè)請(qǐng)求,服務(wù)器可能就吃不消了(又不是只有一兩個(gè)人在訪問這個(gè)頁面)。
因此優(yōu)點(diǎn)就很明顯了:不僅可以減輕服務(wù)器的壓力,而且可以讓加載好的頁面更快地呈現(xiàn)在用戶面前(用戶體驗(yàn)好)。
三、怎么實(shí)現(xiàn)?
關(guān)鍵點(diǎn)如下:
1、頁面中的img元素,如果沒有src屬性,瀏覽器就不會(huì)發(fā)出請(qǐng)求去下載圖片(也就沒有請(qǐng)求咯,也就提高性能咯),一旦通過javascript設(shè)置了圖片路徑,瀏覽器才會(huì)送請(qǐng)求。有點(diǎn)按需分配的意思,你不想看,就不給你看,你想看了就給你看~
2、如何獲取正真的路徑,這個(gè)簡單,現(xiàn)在正真的路徑存在元素的“data-url”(這個(gè)名字起個(gè)自己認(rèn)識(shí)好記的就行)屬性里,要用的時(shí)候就取出來,再設(shè)置;
3、開始比較之前,先了解一些基本的知識(shí),比如說如何獲取某個(gè)元素的尺寸大小、滾動(dòng)條滾動(dòng)距離及偏移位置距離;
1)屏幕可視窗口大小:對(duì)應(yīng)于圖中1、2位置處
原生方法:window.innerHeight 標(biāo)準(zhǔn)瀏覽器及IE9+ || document.documentElement.clientHeight 標(biāo)準(zhǔn)瀏覽器及低版本IE標(biāo)準(zhǔn)模式 || document.body.clientHeight 低版本混雜模式
jQuery方法: $(window).height()
2)瀏覽器窗口頂部與文檔頂部之間的距離,也就是滾動(dòng)條滾動(dòng)的距離:也就是圖中3、4處對(duì)應(yīng)的位置;
原生方法:window.pagYoffset――IE9+及標(biāo)準(zhǔn)瀏覽器 || document.documentElement.scrollTop 兼容ie低版本的標(biāo)準(zhǔn)模式 || document.body.scrollTop 兼容混雜模式;
jQuery方法:$(document).scrollTop();
3)獲取元素的尺寸:對(duì)應(yīng)于圖中5、6位置處;左邊jquery方法,右邊原生方法
$(o).width() = o.style.width;
$(o).innerWidth() = o.style.width+o.style.padding;
$(o).outerWidth() = o.offsetWidth = o.style.width+o.style.padding+o.style.border;
$(o).outerWidth(true) = o.style.width+o.style.padding+o.style.border+o.style.margin;
注意:要使用原生的style.xxx方法獲取屬性,這個(gè)元素必須已經(jīng)有內(nèi)嵌的樣式,如<div style="...."></div>;
如果原先是通過外部或內(nèi)部樣式表定義css樣式,必須使用o.currentStyle[xxx] ||document.defaultView.getComputedStyle(0)[xxx]來獲取樣式值
4)獲取元素的位置信息:對(duì)應(yīng)與圖中7、8位置處
1)返回元素相對(duì)于文檔document頂部、左邊的距離;
jQuery:$(o).offset().top元素距離文檔頂?shù)木嚯x,$(o).offset().left元素距離文檔左邊緣的距離
原生:getoffsetTop(),高程上有具體說明,這邊就忽略了;
順便提一下返回元素相對(duì)于第一個(gè)以定位的父元素的偏移距離,注意與上面偏移距的區(qū)別;
jQuery:position()返回一個(gè)對(duì)象,$(o).position().left = style.left,$(o).position().top = style.top;
4、知道如何獲取元素尺寸、偏移距離后,接下來一個(gè)問題就是:如何判斷某個(gè)元素進(jìn)入或者即將進(jìn)入可視窗口區(qū)域?下面也通過一張圖來說明問題。

1)外面最大的框?yàn)閷?shí)際頁面的大小,中間淺藍(lán)色的框代表父元素的大小,對(duì)象1~8代表元素位于頁面上的實(shí)際位置;以水平方向來做如下說明!
2)對(duì)象8左邊界相對(duì)于頁面左邊界的偏移距離(offsetLeft)大于父元素右邊界相對(duì)于頁面左邊界的距離,此時(shí)可判讀元素位于父元素之外;
3)對(duì)象7左邊界跨過了父元素右邊界,此時(shí):對(duì)象7左邊界相對(duì)于頁面左邊界的偏移距離(offsetLeft)小于 父元素右邊界相對(duì)于頁面左邊界的距離,因此對(duì)象7就進(jìn)入了父元素可視區(qū);
4)在對(duì)象6的位置處,對(duì)象5的右邊界與頁面左邊界的距離 大于 父元素左邊界與頁面左邊界的距離;
5)在對(duì)象5位置處時(shí),對(duì)象5的右邊界與頁面左邊界的距離 小于 父元素左邊界與頁面左邊界的距離;此時(shí),可判斷元素處于父元素可視區(qū)外;
6)因此水平方向必須買足兩個(gè)條件,才能說明元素位于父元素的可視區(qū)內(nèi);同理垂直方向也必須滿足兩個(gè)條件;具體見下文的源碼;
四、擴(kuò)展為jquery插件
使用方法:$("selector").scrollLoad({ 參數(shù)在代碼中有說明 })
(function($) { $.fn.scrollLoading = function(options) { var defaults = {  // 在html標(biāo)簽中存放的屬性名稱;  attr: "data-url",  // 父元素默認(rèn)為window  container: window,  callback: $.noop }; // 不管有沒有傳入?yún)?shù),先合并再說; var params = $.extend({}, defaults, options || {}); // 把父元素轉(zhuǎn)為jquery對(duì)象; var container = $(params.container); // 新建一個(gè)數(shù)組,然后調(diào)用each方法,用于存儲(chǔ)每個(gè)dom對(duì)象相關(guān)的數(shù)據(jù); params.cache = []; $(this).each(function() {  // 取出jquery對(duì)象中每個(gè)dom對(duì)象的節(jié)點(diǎn)類型,取出每個(gè)dom對(duì)象上設(shè)置的圖片路徑  var node = this.nodeName.toLowerCase(), url = $(this).attr(params["attr"]);  //重組,把每個(gè)dom對(duì)象上的屬性存為一個(gè)對(duì)象;  var data = {  obj: $(this),  tag: node,  url: url  };  // 把這個(gè)對(duì)象加到一個(gè)數(shù)組中;  params.cache.push(data); }); var callback = function(call) {  if ($.isFunction(params.callback)) {  params.callback.call(call);  } };  //每次觸發(fā)滾動(dòng)事件時(shí),對(duì)每個(gè)dom元素與container元素進(jìn)行位置判斷,如果滿足條件,就把路徑賦予這個(gè)dom元素! var loading = function() {  // 獲取父元素的高度  var contHeight = container.outerHeight();  var contWidth = container.outerWidth();  // 獲取父元素相對(duì)于文檔頁頂部的距離,這邊要注意了,分為以下兩種情況;  if (container.get(0) === window) {  // 第一種情況父元素為window,獲取瀏覽器滾動(dòng)條已滾動(dòng)的距離;$(window)沒有offset()方法;  var contop = $(window).scrollTop();  var conleft = $(window).scrollLeft();  } else {  // 第二種情況父元素為非window元素,獲取它的滾動(dòng)條滾動(dòng)的距離;  var contop = container.offset().top;  var conleft = container.offset().left;  }  $.each(params.cache, function(i, data) {  var o = data.obj, tag = data.tag, url = data.url, post, posb, posl, posr;  if (o) {   //對(duì)象頂部與文檔頂部之間的距離,如果它小于父元素底部與文檔頂部的距離,則說明垂直方向上已經(jīng)進(jìn)入可視區(qū)域了;   post = o.offset().top - (contop + contHeight);   //對(duì)象底部與文檔頂部之間的距離,如果它大于父元素頂部與文檔頂部的距離,則說明垂直方向上已經(jīng)進(jìn)入可視區(qū)域了;   posb = o.offset().top + o.height() - contop;   // 水平方向上同理;   posl = o.offset().left - (conleft + contWidth);   posr = o.offset().left + o.width() - conleft;   // 只有當(dāng)這個(gè)對(duì)象是可視的,并且這四個(gè)條件都滿足時(shí),才能給這個(gè)對(duì)象賦予圖片路徑;   if ( o.is(':visible') && (post < 0 && posb > 0) && (posl < 0 && posr > 0) ) {   if (url) {    //在瀏覽器窗口內(nèi)    if (tag === "img") {    //設(shè)置圖片src    callback(o.attr("src", url));    } else {    // 設(shè)置除img之外元素的背景url    callback(o.css("background-image", "url("+ url +")"));    }   } else {    // 無地址,直接觸發(fā)回調(diào)    callback(o);   }   // 給對(duì)象設(shè)置完圖片路徑之后,把params.cache中的對(duì)象給清除掉;對(duì)象再進(jìn)入可視區(qū),就不再進(jìn)行重復(fù)設(shè)置了;   data.obj = null;   }  }  }); }; //加載完畢即執(zhí)行 loading(); //滾動(dòng)執(zhí)行 container.bind("scroll", loading); };})(jQuery);本文已被整理到了《jquery圖片加載方法匯總》 ,歡迎大家學(xué)習(xí)閱讀。
以上就是滾動(dòng)加載圖片實(shí)現(xiàn)原理的詳細(xì)內(nèi)容介紹,希望對(duì)大家的學(xué)習(xí)有所幫助。
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注