滾動載入圖片(懶載入)實現原理
本文主要通過以下幾方面來說明懶載入技術的原理,個人前端小菜,有錯誤請多多指出
一、什麼是圖片滾動載入?
通俗的講就是:當訪問一個頁面的時候,先把img
元素或是其他元素的背景圖片路徑替換成一張大小為1*1px圖片的路徑(這樣就只需請求一次),只有當圖片出現在瀏覽器的可視區域內時,才設定圖片正真的路徑,讓圖片顯示出來。這就是圖片懶載入。
二、為什要使用這個技術?
比如一個頁面中有很多圖片,如淘寶、京東首頁等等,如果一上來就傳送這麼多請求,頁面載入就會很漫長,如果js
檔案都放在了文件的底部,恰巧頁面的頭部又依賴這個js
檔案,那就不好辦了。更為要命的是:一上來就傳送百八十個請求,伺服器可能就吃不消了(又不是隻有一兩個人在訪問這個頁面)。
因此優點就很明顯了:不僅可以減輕伺服器的壓力,而且可以讓載入好的頁面更快地呈現在使用者面前(使用者體驗好)。
三、怎麼實現?
關鍵點如下:
1、頁面中的img
元素,如果沒有src
屬性,瀏覽器就不會發出請求去下載圖片(也就沒有請求咯,也就提高效能咯),一旦通過javascript
設定了圖片路徑,瀏覽器才會送請求。有點按需分配的意思,你不想看,就不給你看,你想看了就給你看~
2、如何獲取正真的路徑,這個簡單,現在正真的路徑存在元素的“data-url
”(這個名字起個自己認識好記的就行)屬性裡,要用的時候就取出來,再設定;
3、開始比較之前,先了解一些基本的知識,比如說如何獲取某個元素的尺寸大小、滾動條滾動距離及偏移位置距離;
1)螢幕可視視窗大小:對應於圖中1、2位置處
原生方法:window.innerHeight
標準瀏覽器及IE9+ || document.documentElement.clientHeight
標準瀏覽器及低版本IE標準模式 || document.body.clientHeight
低版本混雜模式
jQuery方法: $(window).height()
2)瀏覽器視窗頂部與文件頂部之間的距離,也就是滾動條滾動的距離:也就是圖中3、4處對應的位置;
原生方法:window.pagYoffset
——IE9+及標準瀏覽器 || document.documentElement.scrollTop
相容ie低版本的標準模式 || document.body.scrollTop
相容混雜模式;
jQuery方法:$(document).scrollTop();
3)獲取元素的尺寸:對應於圖中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
方法獲取屬性,這個元素必須已經有內嵌的樣式,如<div style="...."></div>
;
如果原先是通過外部或內部樣式表定義css
樣式,必須使用o.currentStyle[xxx] ||document.defaultView.getComputedStyle(0)[xxx]
來獲取樣式值
4)獲取元素的位置資訊:對應與圖中7、8位置處
1)返回元素相對於文件document
頂部、左邊的距離;
jQuery:$(o).offset().top
元素距離文件頂的距離,$(o).offset().left
元素距離文件左邊緣的距離
原生:getoffsetTop()
,高程上有具體說明,這邊就忽略了;
順便提一下返回元素相對於第一個以定位的父元素的偏移距離,注意與上面偏移距的區別;
jQuery:position()
返回一個物件,$(o).position().left = style.left
,$(o).position().top = style.top;
4、知道如何獲取元素尺寸、偏移距離後,接下來一個問題就是:如何判斷某個元素進入或者即將進入可視視窗區域?下面也通過一張圖來說明問題。
1)外面最大的框為實際頁面的大小,中間淺藍色的框代表父元素的大小,物件1~8代表元素位於頁面上的實際位置;以水平方向來做如下說明!
2)物件8左邊界相對於頁面左邊界的偏移距離(offsetLeft
)大於父元素右邊界相對於頁面左邊界的距離,此時可判讀元素位於父元素之外;
3)物件7左邊界跨過了父元素右邊界,此時:物件7左邊界相對於頁面左邊界的偏移距離(offsetLeft
)小於 父元素右邊界相對於頁面左邊界的距離,因此物件7就進入了父元素可視區;
4)在物件6的位置處,物件5的右邊界與頁面左邊界的距離 大於 父元素左邊界與頁面左邊界的距離;
5)在物件5位置處時,物件5的右邊界與頁面左邊界的距離 小於 父元素左邊界與頁面左邊界的距離;此時,可判斷元素處於父元素可視區外;
6)因此水平方向必須買足兩個條件,才能說明元素位於父元素的可視區內;同理垂直方向也必須滿足兩個條件;具體見下文的原始碼;
四、擴充套件為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);
五、參考:
1、jQuery.lazyload
詳解
2、張大大:http://www.zhangxinxu.com/wordpress/?p=1259
3、Jquery圖片延遲載入外掛jquery.lazyload
. http://www.daxueit.com/article/3944.html
4、jQuery.lazyload
實現延時載入詳解步驟 http://www.daxueit.com/article/21.html
5、jquery lazyload
延遲載入技術的實現原理分析 http://www.daxueit.com/article/3777.html
6、Lazyload
延遲載入效果
7、圖片延遲載入(lazyload
)的實現原理
相關文章
- 一起來實現圖片滾動懶載入
- 圖片懶載入原理
- 圖片懶載入實現
- 圖片懶載入js實現JS
- [譯] 原生實現圖片懶載入
- React如何實現圖片懶載入React
- 實現圖片懶載入(throttle, debounce)
- 圖片懶載入
- 手把手實現圖片懶載入+封裝vue懶載入元件封裝Vue元件
- 圖片預載入和懶載入
- 圖片懶載入(IntersectionObserver)Server
- 實現圖片懶載入的三種方式
- 圖片懶載入踩坑
- 圖片懶載入大白話
- Js圖片懶載入(lazyload)JS
- 單張圖片懶載入
- 小說APP原始碼的圖片載入方式,懶載入和預載入的實現APP原始碼
- 微信小程式--實現圖片懶載入(lazyload)微信小程式
- Vue實現一個圖片懶載入外掛Vue
- 30行Javascript程式碼實現圖片懶載入JavaScript
- 頁面圖片預載入與懶載入策略
- 移動端無限滾動載入 js實現原理JS
- glide圖片載入原理IDE
- 圖片預載入,圖片懶載入,和jsonp中的一個疑問JSON
- vue圖片懶載入lazy-loadVue
- 前端優化之圖片懶載入前端優化
- 深入理解React:懶載入(lazy)實現原理React
- ECMAScript擴充套件 -12 【圖片的預載入與懶載入】套件
- layui圖片懶載入-loading佔點陣圖UI
- 關於懶載入原理
- 圖片預載入和懶載入(附上一個小demo瀑布流)
- 如何實現圖片預載入和載入進度條
- Vue圖片懶載入之lazyload外掛使用Vue
- 小程式之圖片瀑布流(最全實現方式,額外加送懶載入)
- 直播平臺搭建,vue中實現圖片懶載入的幾種方法Vue
- 懶載入和預載入
- 懶載入
- Xamarin.Forms: 無限滾動的ListView(懶載入方式)ORMView