滾動加載圖片(懶加載)實現原理

滾動加載圖片(懶加載)實現原理

本文主要根據javascript

1、什麼是圖片滾動加載?css

通俗的講就是:當訪問一個頁面的時候,先把img元素或是其餘元素的背景圖片路徑替換成一張大小爲1*1px圖片的路徑(這樣就只需請求一次),只有當圖片出如今瀏覽器的可視區域內時,才設置圖片正真的路徑,讓圖片顯示出來。這就是圖片懶加載。html

2、爲什要使用這個技術?java

好比一個頁面中有不少圖片,如淘寶、京東首頁等等,若是一上來就發送這麼多請求,頁面加載就會很漫長,若是js文件都放在了文檔的底部,恰巧頁面的頭部又依賴這個js文件,那就很差辦了。更爲要命的是:一上來就發送百八十個請求,服務器可能就吃不消了(又不是隻有一兩我的在訪問這個頁面)。node

所以優勢就很明顯了:不只能夠減輕服務器的壓力,並且可讓加載好的頁面更快地呈如今用戶面前(用戶體驗好)。jquery

3、怎麼實現?windows

關鍵點以下:數組

一、頁面中的img元素,若是沒有src屬性,瀏覽器就不會發出請求去下載圖片(也就沒有請求咯,也就提升性能咯),一旦經過javascript設置了圖片路徑,瀏覽器纔會送請求。有點按需分配的意思,你不想看,就不給你看,你想看了就給你看~瀏覽器

二、如何獲取正真的路徑,這個簡單,如今正真的路徑存在元素的「data-url」(這個名字起個本身認識好記的就行)屬性裏,要用的時候就取出來,再設置;服務器

三、開始比較以前,先了解一些基本的知識,好比說如何獲取某個元素的尺寸大小、滾動條滾動距離及偏移位置距離;滾動加載圖片(懶加載)實現原理

1)屏幕可視窗口大小:對應於圖中一、2位置處

原生方法:windows.innerHeight 標準瀏覽器及IE9+ || document.documentElement.clientHeight 標準瀏覽器及低版本IE標準模式 ||

document.body.clientHeight 低版本混雜模式

jQuery方法: $(window).height()

2)瀏覽器窗口頂部與文檔頂部之間的距離,也就是滾動條滾動的距離:也就是圖中三、4處對應的位置;

原生方法:window.pagYoffset——IE9+及標準瀏覽器 || document.documentElement.scrollTop 兼容ie低版本的標準模式 ||

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

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

3)獲取元素的尺寸:對應於圖中五、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方法獲取屬性,這個元素必須已經有內嵌的樣式,如

若是原先是經過外部或內部樣式表定義css樣式,必須使用o.currentStyle[xxx] || document.defaultView.getComputedStyle(0)[xxx]來獲取樣式值

4)獲取元素的位置信息:對應與圖中七、8位置處

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

jQuery:$(o).offset().top元素距離文檔頂的距離,$(o).offset().left元素距離文檔左邊緣的距離

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

順便提一下返回元素相對於第一個以定位的父元素的偏移距離,注意與上面偏移距的區別;

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

四、知道如何獲取元素尺寸、偏移距離後,接下來一個問題就是:如何判斷某個元素進入或者即將進入可視窗口區域?下面也經過一張圖來講明問題。

滾動加載圖片(懶加載)實現原理

1)外面最大的框爲實際頁面的大小,中間淺藍色的框表明父元素的大小,對象1~8表明元素位於頁面上的實際位置;以水平方向來作以下說明!

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

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

頁面左邊界的距離,所以對象7就進入了父元素可視區;

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

5)在對象5位置處時,對象5的右邊界與頁面左邊界的距離 小於 父元素左邊界與頁面左邊界的距離;此時,可判斷元素處於父元素可視區外;

6)所以水平方向必須買足兩個條件,才能說明元素位於父元素的可視區內;同理垂直方向也必須知足兩個條件;具體見下文的源碼;

4、擴展爲jquery插件

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

(function($) {
    $.fn.scrollLoading = function(options) { var defaults = { // 在html標籤中存放的屬性名稱; attr: "data-url", // 父元素默認爲window container: window, callback: $.noop }; // 無論有沒有傳入參數,先合併再說; var params = $.extend({}, defaults, options || {}); // 把父元素轉爲jquery對象; var container = $(params.container); // 新建一個數組,而後調用each方法,用於存儲每一個dom對象相關的數據; params.cache = []; $(this).each(function() { // 取出jquery對象中每一個dom對象的節點類型,取出每一個dom對象上設置的圖片路徑 var node = this.nodeName.toLowerCase(), url = $(this).attr(params["attr"]); //重組,把每一個dom對象上的屬性存爲一個對象; var data = { obj: $(this), tag: node, url: url }; // 把這個對象加到一個數組中; params.cache.push(data); }); var callback = function(call) { if ($.isFunction(params.callback)) { params.callback.call(call); } }; //每次觸發滾動事件時,對每一個dom元素與container元素進行位置判斷,若是知足條件,就把路徑賦予這個dom元素! var loading = function() { // 獲取父元素的高度 var contHeight = container.outerHeight(); var contWidth = container.outerWidth(); // 獲取父元素相對於文檔頁頂部的距離,這邊要注意了,分爲如下兩種狀況; if (container.get(0) === window) { // 第一種狀況父元素爲window,獲取瀏覽器滾動條已滾動的距離;$(window)沒有offset()方法; var contop = $(window).scrollTop(); var conleft = $(window).scrollLeft(); } else { // 第二種狀況父元素爲非window元素,獲取它的滾動條滾動的距離; 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) { //對象頂部與文檔頂部之間的距離,若是它小於父元素底部與文檔頂部的距離,則說明垂直方向上已經進入可視區域了; post = o.offset().top - (contop + contHeight); //對象底部與文檔頂部之間的距離,若是它大於父元素頂部與文檔頂部的距離,則說明垂直方向上已經進入可視區域了; posb = o.offset().top + o.height() - contop; // 水平方向上同理; posl = o.offset().left - (conleft + contWidth); posr = o.offset().left + o.width() - conleft; // 只有當這個對象是可視的,而且這四個條件都知足時,才能給這個對象賦予圖片路徑; if ( o.is(':visible') && (post < 0 && posb > 0) && (posl < 0 && posr > 0) ) { if (url) { //在瀏覽器窗口內 if (tag === "img") { //設置圖片src callback(o.attr("src", url)); } else { // 設置除img以外元素的背景url callback(o.css("background-image", "url("+ url +")")); } } else { // 無地址,直接觸發回調 callback(o); } // 給對象設置完圖片路徑以後,把params.cache中的對象給清除掉;對象再進入可視區,就再也不進行重複設置了; data.obj = null; } } }); }; //加載完畢即執行 loading(); //滾動執行 container.bind("scroll", loading); }; })(jQuery); 
相關文章
相關標籤/搜索