2019-07-02

一伟桅、什么是圖片滾動加載?

  通俗的講就是:當(dāng)訪問一個頁面的時候,先把img元素或是其他元素的背景圖片路徑替換成一張大小為1*1px圖片的路徑(這樣就只需請求一次),只有當(dāng)圖片出現(xiàn)在瀏覽器的可視區(qū)域內(nèi)時击你,才設(shè)置圖片正真的路徑,讓圖片顯示出來谎柄。這就是圖片懶加載。

二惯雳、為什要使用這個技術(shù)朝巫?

  比如一個頁面中有很多圖片,如淘寶石景、京東首頁等等劈猿,如果一上來就發(fā)送這么多請求,頁面加載就會很漫長潮孽,如果js文件都放在了文檔的底部揪荣,恰巧頁面的頭部又依賴這個js文件,那就不好辦了往史。更為要命的是:一上來就發(fā)送百八十個請求仗颈,服務(wù)器可能就吃不消了(又不是只有一兩個人在訪問這個頁面)。

  因此優(yōu)點(diǎn)就很明顯了:不僅可以減輕服務(wù)器的壓力椎例,而且可以讓加載好的頁面更快地呈現(xiàn)在用戶面前(用戶體驗(yàn)好)挨决。

三、怎么實(shí)現(xiàn)订歪?

  關(guān)鍵點(diǎn)如下:

? ? ? 1脖祈、頁面中的img元素,如果沒有src屬性刷晋,瀏覽器就不會發(fā)出請求去下載圖片(也就沒有請求咯盖高,也就提高性能咯)慎陵,一旦通過javascript設(shè)置了圖片路徑,瀏覽器才會送請求喻奥。有點(diǎn)按需分配的意思席纽,你不想看,就不給你看映凳,你想看了就給你看~

  2胆筒、如何獲取正真的路徑,這個簡單诈豌,現(xiàn)在正真的路徑存在元素的“data-url”(這個名字起個自己認(rèn)識好記的就行)屬性里仆救,要用的時候就取出來,再設(shè)置矫渔;

3彤蔽、開始比較之前,先了解一些基本的知識庙洼,比如說如何獲取某個元素的尺寸大小顿痪、滾動條滾動距離及偏移位置距離;

  1)屏幕可視窗口大杏凸弧:對應(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)瀏覽器窗口頂部與文檔頂部之間的距離,也就是滾動條滾動的距離:也就是圖中3石咬、4處對應(yīng)的位置揩悄;

    原生方法:window.pagYoffset——IE9+及標(biāo)準(zhǔn)瀏覽器 || document.documentElement.scrollTop 兼容ie低版本的標(biāo)準(zhǔn)模式 ||

         document.body.scrollTop 兼容混雜模式;

? ? ?   jQuery方法:$(document).scrollTop();?

  3)獲取元素的尺寸:對應(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方法獲取屬性焕窝,這個元素必須已經(jīng)有內(nèi)嵌的樣式蹬挺,如<div style="...."></div>;

    如果原先是通過外部或內(nèi)部樣式表定義css樣式它掂,必須使用o.currentStyle[xxx] || document.defaultView.getComputedStyle(0)[xxx]來獲取樣式值

  4)獲取元素的位置信息:對應(yīng)與圖中7巴帮、8位置處

    1)返回元素相對于文檔document頂部、左邊的距離虐秋;

    jQuery:$(o).offset().top元素距離文檔頂?shù)木嚯x晰韵,$(o).offset().left元素距離文檔左邊緣的距離

    原生:getoffsetTop(),高程上有具體說明熟妓,這邊就忽略了雪猪;

     ?順便提一下返回元素相對于第一個以定位的父元素的偏移距離,注意與上面偏移距的區(qū)別起愈;

? ?   ? jQuery:position()返回一個對象只恨,$(o).position().left = style.left译仗,$(o).position().top = style.top;

  4官觅、知道如何獲取元素尺寸纵菌、偏移距離后,接下來一個問題就是:如何判斷某個元素進(jìn)入或者即將進(jìn)入可視窗口區(qū)域休涤?下面也通過一張圖來說明問題咱圆。

    1)外面最大的框?yàn)閷?shí)際頁面的大小,中間淺藍(lán)色的框代表父元素的大小功氨,對象1~8代表元素位于頁面上的實(shí)際位置序苏;以水平方向來做如下說明!

    2)對象8左邊界相對于頁面左邊界的偏移距離(offsetLeft)大于父元素右邊界相對于頁面左邊界的距離捷凄,此時可判讀元素位于父元素之外忱详;

    3)對象7左邊界跨過了父元素右邊界,此時:對象7左邊界相對于頁面左邊界的偏移距離(offsetLeft)小于?父元素右邊界相對于

      頁面左邊界的距離跺涤,因此對象7就進(jìn)入了父元素可視區(qū)匈睁;

    4)在對象6的位置處,對象5的右邊界與頁面左邊界的距離?大于?父元素左邊界與頁面左邊界的距離桶错;

    5)在對象5位置處時航唆,對象5的右邊界與頁面左邊界的距離?小于?父元素左邊界與頁面左邊界的距離;此時院刁,可判斷元素處于父元素可視區(qū)外糯钙;

    6)因此水平方向必須買足兩個條件,才能說明元素位于父元素的可視區(qū)內(nèi)黎比;同理垂直方向也必須滿足兩個條件;具體見下文的源碼鸳玩;

四阅虫、擴(kuò)展為jquery插件

  使用方法:$("selector").scrollLoad({ 參數(shù)在代碼中有說明?})

(function($) {

? ? $.fn.scrollLoading =function(options) {

? ? ? ? vardefaults = {

? ? ? ? ? ? // 在html標(biāo)簽中存放的屬性名稱;attr: "data-url",

? ? ? ? ? ? // 父元素默認(rèn)為window? ? ? ? ? ? container: window,

? ? ? ? ? ? callback: $.noop

? ? ? ? };

? ? ? ? // 不管有沒有傳入?yún)?shù)不跟,先合并再說颓帝;varparams = $.extend({}, defaults, options || {});

? ? ? ? // 把父元素轉(zhuǎn)為jquery對象;varcontainer = $(params.container);

? ? ? ? // 新建一個數(shù)組窝革,然后調(diào)用each方法购城,用于存儲每個dom對象相關(guān)的數(shù)據(jù);params.cache = [];

? ? ? ? $(this).each(function() {

? ? ? ? ? ? // 取出jquery對象中每個dom對象的節(jié)點(diǎn)類型虐译,取出每個dom對象上設(shè)置的圖片路徑varnode =this.nodeName.toLowerCase(), url = $(this).attr(params["attr"]);

? ? ? ? ? ? //重組瘪板,把每個dom對象上的屬性存為一個對象;vardata = {

? ? ? ? ? ? ? ? obj: $(this),

? ? ? ? ? ? ? ? tag: node,

? ? ? ? ? ? ? ? url: url

? ? ? ? ? ? };

? ? ? ? ? ? // 把這個對象加到一個數(shù)組中漆诽;? ? ? ? ? ? params.cache.push(data);

? ? ? ? });

? ? ? ? varcallback =function(call) {

? ? ? ? ? ? if ($.isFunction(params.callback)) {

? ? ? ? ? ? ? ? params.callback.call(call);

? ? ? ? ? ? }

? ? ? ? };


? ? ? ? //每次觸發(fā)滾動事件時侮攀,對每個dom元素與container元素進(jìn)行位置判斷锣枝,如果滿足條件,就把路徑賦予這個dom元素兰英!varloading =function() {

? ? ? ? ? ? // 獲取父元素的高度varcontHeight = container.outerHeight();

? ? ? ? ? ? varcontWidth = container.outerWidth();

? ? ? ? ? ? // 獲取父元素相對于文檔頁頂部的距離撇叁,這邊要注意了,分為以下兩種情況畦贸;if(container.get(0) === window) {

? ? ? ? ? ? ? ? // 第一種情況父元素為window陨闹,獲取瀏覽器滾動條已滾動的距離;$(window)沒有offset()方法薄坏;varcontop = $(window).scrollTop();

? ? ? ? ? ? ? ? varconleft = $(window).scrollLeft();

? ? ? ? ? ? } else {

? ? ? ? ? ? ? ? // 第二種情況父元素為非window元素趋厉,獲取它的滾動條滾動的距離;varcontop = container.offset().top;

? ? ? ? ? ? ? ? varconleft = container.offset().left;

? ? ? ? ? ? }

? ? ? ? ? ? $.each(params.cache, function(i, data) {

? ? ? ? ? ? ? ? varo = data.obj, tag = data.tag, url = data.url, post, posb, posl, posr;

? ? ? ? ? ? ? ? if (o) {

? ? ? ? ? ? ? ? ? ? //對象頂部與文檔頂部之間的距離颤殴,如果它小于父元素底部與文檔頂部的距離觅廓,則說明垂直方向上已經(jīng)進(jìn)入可視區(qū)域了;post = o.offset().top - (contop + contHeight);

? ? ? ? ? ? ? ? ? ? //對象底部與文檔頂部之間的距離涵但,如果它大于父元素頂部與文檔頂部的距離杈绸,則說明垂直方向上已經(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)這個對象是可視的瞳脓,并且這四個條件都滿足時,才能給這個對象賦予圖片路徑澈侠;if( o.is(':visible') && (post < 0 && posb > 0) && (posl < 0 && posr > 0) ) {

? ? ? ? ? ? ? ? ? ? ? ? if (url) {

? ? ? ? ? ? ? ? ? ? ? ? ? ? //在瀏覽器窗口內(nèi)if(tag === "img") {

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //設(shè)置圖片srccallback(o.attr("src", url));

? ? ? ? ? ? ? ? ? ? ? ? ? ? } else {

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? // 設(shè)置除img之外元素的背景urlcallback(o.css("background-image", "url("+ url +")"));

? ? ? ? ? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? ? ? ? } else {

? ? ? ? ? ? ? ? ? ? ? ? ? ? // 無地址劫侧,直接觸發(fā)回調(diào)? ? ? ? ? ? ? ? ? ? ? ? ? ? callback(o);

? ? ? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? ? ? ? // 給對象設(shè)置完圖片路徑之后,把params.cache中的對象給清除掉哨啃;對象再進(jìn)入可視區(qū)烧栋,就不再進(jìn)行重復(fù)設(shè)置了;data.obj =null;

? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? }

? ? ? ? ? ? });

? ? ? ? };

? ? ? ? //加載完畢即執(zhí)行? ? ? ? loading();

? ? ? ? //滾動執(zhí)行container.bind("scroll", loading);

? ? };

})(jQuery);

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末拳球,一起剝皮案震驚了整個濱河市审姓,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌祝峻,老刑警劉巖魔吐,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異莱找,居然都是意外死亡酬姆,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進(jìn)店門奥溺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來辞色,“玉大人,你說我怎么就攤上這事浮定∫В” “怎么了诱篷?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長雳灵。 經(jīng)常有香客問我棕所,道長,這世上最難降的妖魔是什么悯辙? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任琳省,我火速辦了婚禮,結(jié)果婚禮上躲撰,老公的妹妹穿的比我還像新娘针贬。我一直安慰自己,他們只是感情好拢蛋,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布桦他。 她就那樣靜靜地躺著,像睡著了一般谆棱。 火紅的嫁衣襯著肌膚如雪快压。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天垃瞧,我揣著相機(jī)與錄音蔫劣,去河邊找鬼。 笑死个从,一個胖子當(dāng)著我的面吹牛脉幢,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播嗦锐,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼嫌松,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了奕污?” 一聲冷哼從身側(cè)響起萎羔,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎菊值,沒想到半個月后外驱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體育灸,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡腻窒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了磅崭。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片儿子。...
    茶點(diǎn)故事閱讀 39,965評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖砸喻,靈堂內(nèi)的尸體忽然破棺而出柔逼,到底是詐尸還是另有隱情蒋譬,我是刑警寧澤,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布愉适,位于F島的核電站犯助,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏维咸。R本人自食惡果不足惜剂买,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望癌蓖。 院中可真熱鬧瞬哼,春花似錦、人聲如沸租副。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽用僧。三九已至结胀,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間永毅,已是汗流浹背把跨。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留沼死,地道東北人着逐。 一個月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像意蛀,于是被迫代替她去往敵國和親耸别。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評論 2 355

推薦閱讀更多精彩內(nèi)容