DIV CSS 佈局教程網

 DIV+CSS佈局教程網 >> 網頁腳本 >> JavaScript入門知識 >> 關於JavaScript >> LazyLoad 延遲加載(按需加載)
LazyLoad 延遲加載(按需加載)
編輯:關於JavaScript     
1:實際需求
  大型網站往往很矛盾,想用戶在首頁看到更多東西,又不想浪費太多服務器流量。比如一個有3屏的首頁。可能50%的用戶進首頁的目的是點擊首頁的連接,到子頁面。
那麼我們的網站卻為100%的用戶加載了 3個 屏幕的所有內容。如果可以按需加載內容。就可以節約更多資源,做更多好的應用。

2:解決方案
  用客戶端語言來判斷用戶當前的可視范圍,只加載用戶可視范圍的內容。最主要的是圖片。因為文字信息,相對較小,其他多媒體內容相對占用服務器流量更多。
3:演示例子(最後提供)
4:解析
  首先我們要分析下,這個效果會有一個 最外面的容器。他包涵了裡面需要延遲加載一些內容。容器一般可能是浏覽器窗口本身(window),或者一個有滾動條的DIV。
OK,我們必須獲取這個容器的一些參數。比如 可視寬度,可視高度,水平卷去寬度,垂直卷去高度。我使用下面的程序。
  4.1:獲取容器對象屬性

復制代碼 代碼如下:
_this.docInfo=function(){//獲取容器的相關信息
var d={},db= (wf)? document.body : warpper,
dd=(wf) ? document.documentElement : warpper;
if(sys.ie){
d.offh=dd.offsetHeight;//可視區域H
d.offw=dd.offsetWidth;//可視區域W
}else{
if(wf){
d.offw=window.innerWidth;//可視區域H
d.offh=window.innerHeight;//可視區域W
}else{
d.offh=dd.offsetHeight;//可視區域H
d.offw=dd.offsetWidth;//可視區域W
}
}
d.jtop=(wf) ? db.scrollTop+dd.scrollTop : db.scrollTop ;//垂直卷去高度
d.jleft=(wf) ? db.scrollLeft+dd.scrollLeft : db.scrollLeft;//水平卷去寬度
//被卷去的寬度 window 使用兩個相加 div的卷曲就直接使用scrollLeft就OK
$j("bbb").innerHTML=d.offh+','+d.offw+','+d.jtop+','+d.jleft
return d;
}
//注意在非IE 浏覽器下 獲取非window對象的可視區域 使用offsetHeight 和 offsetWidth (跟IE 一樣)
//在非IE 下獲取 window對象的可視區域 則要使用 window.innerWidth 和window.innerHeight
//也就是說在非IE 下的 window 和 非window 對象的 可視區域獲取是不一樣的。


  4.2:獲取加載內容的信息
    我們主要獲取加載對象距離 頁面容器對象的距離 。
IE 6 7會有個BUG
復制代碼 代碼如下:
wtop=sys.ie ? (sys.ie[1]=='6.0' || sys.ie[1]=='7.0') ? 0 : warpper.offsetTop : warpper.offsetTop,
wleft=sys.ie ? (sys.ie[1]=='6.0' || sys.ie[1]=='7.0') ? 0 : warpper.offsetLeft : warpper.offsetLeft,

復制代碼 代碼如下:
getoff=function(o){//獲取IMG對象的 offw and offh
o.innerHTML=(o.offsetTop-wtop) +','+ (o.offsetLeft-wleft);
return (o.offsetTop-wtop) +','+ (o.offsetLeft-wleft);
//注意 o.offsetTop 在chrome下要等window.onload以後才能正確獲取
};

  4.3:加載主程序
    他主要負責加載當前在可視范圍內對象。那麼我們必須去遍歷所有要加載的對象。判斷對象是否在當前的加載中。
然後加載他。我下面會有一個圖。(方法可能不太好)
復制代碼 代碼如下:
_this.Load=function(){
var hereline=[];
hereline[1]=doc.offh+doc.jtop;
hereline[2]=doc.offw+doc.jleft;
for(i=0;i<imgs.length;i++){
if(imgs[i][1] != undefined){//判斷當前對象是否已經加載過
var jj=hereline[1] - imgs[i][1] < doc.offh +130 && hereline[1] - imgs[i][1] > 0 ? true : false,
jjj=hereline[2] - imgs[i][2] < doc.offw +270 && hereline[2] - imgs[i][2] > 0 ? true : false;
if(jj && jjj){
imgall[i].innerHTML+='第'+(++j)+'個加載';
imgs[i][1]=undefined;
}
}
}
if( j >= imgs.length){//判斷是否已經全部加載完畢
//取消時間綁定
alert("已經全部加載完成,程序將不再執行")
warpper.onscroll=null;
warpper.onresize=null;
}
}

我不太喜歡我的判斷程序,但是暫時沒找到,或者我沒理解更好的算法。所以就先用這個了。
大體的意思:用容器的可視高度+容器滾動高度 - 對象距離距離容器距離 > 容器可視 + 對象本身高或寬 就證明在加載范圍。(繞口令)
我們還必須把 已經加載過的對象排除在外。因為加載過的對象也滿足以上公式,同時也可以少判斷一些。
imgs[i][1]=undefined;
if(imgs[i][1] != undefined){//判斷當前對象是否已經加載過
  特別注意(看圖)

看上圖 A B C D。 分別有4個不同的角露在了 可視范圍內。所以這4個對象是需要加載的。

如果只考慮對象的某個點,或者某個線來判斷對象是否在可視范圍,可能帶來不好的體驗。

由於有上面這種情況,也給我們的編程(判斷是否在可視范圍內)增加了難度。

我上面的方法,是可以完成了。(如果有發現BUG ,請給我指點。其實我也有點暈了。)



最後還有幾個技巧,比如

  1:對象全部加載完了。就應該去掉容器對象事件觸發。

  2:盡量優化判斷對象是否在可視范圍,或者遍歷的對象的算法。可以節約很多浏覽器資源。

  3:cloudgamer 還提到一個 延遲觸發,就是快速的滑動滾動條,延遲一下也是一個小的優化。

5:推薦文章

  cloudgamer 的 他講的很詳細,也比我做的要好。所以推薦去學習他的這個效果哦。很多東西我也借鑒他的。

還有就是感謝他的指點。 Lazyload 延遲加載效果
6:我的源碼
復制代碼 代碼如下:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>lazyload</title>
</head>
<body>
<style type="text/css">
body{ margin:0px; padding:0; font-size:12px;}
.jelle_box{width:270px; height:129px; border:1px solid #CCC; float:left;}
</style>
<input type="button" value="重新開始" onclick="lazyload().judge();" />
<div style="width:100%; height:500px; overflow:scroll; border:2px solid #999;" id="jelle_abcd">
<div id="aaa" style="width:2500px; height:800px; margin:10px;">
<div class="jelle_box"></div>
<div class="jelle_box"></div>
<div class="jelle_box"></div>
<div class="jelle_box"></div>
<div class="jelle_box"></div>
<div class="jelle_box"></div>
<div class="jelle_box"></div>
<div class="jelle_box"></div>
<div class="jelle_box"></div>
<div class="jelle_box"></div>
<div class="jelle_box"></div>
<div class="jelle_box"></div>
<div class="jelle_box"></div>
<div class="jelle_box"></div>
<div class="jelle_box"></div>
<div class="jelle_box"></div>
<div class="jelle_box"></div>
<div class="jelle_box"></div>
<div class="jelle_box"></div>
<div class="jelle_box"></div>
<div class="jelle_box"></div>
<div class="jelle_box"></div>
<div class="jelle_box"></div>
<div class="jelle_box"></div>
<div class="jelle_box"></div>
<div class="jelle_box"></div>
<div class="jelle_box"></div>
<div class="jelle_box"></div>
<div class="jelle_box"></div>
<div class="jelle_box"></div>
<div class="jelle_box"></div>
<div class="jelle_box"></div>
<div class="jelle_box"></div>
<div class="jelle_box"></div>
<div class="jelle_box"></div>
<div class="jelle_box"></div>
<div class="jelle_box"></div>
<div class="jelle_box"></div>
<div class="jelle_box"></div>
<div class="jelle_box"></div>
<div class="jelle_box"></div>
<div class="jelle_box"></div>
<div class="jelle_box"></div>
<div class="jelle_box"></div>
<div class="jelle_box"></div>
<div class="jelle_box"></div>
<div class="jelle_box"></div>
<div class="jelle_box"></div>
<div class="jelle_box"></div>
</div>
</div>
<div style=" height:30px" id="bbb"></div>
<script type="text/javascript">
(function(){
window.lazyload=function(){
var _this={},//方法集合
imgsurl=['baidu_logo_2.gif']//最開始是用來加載圖片的。這裡是需要加載圖片的地址集合
imgs=[],//全部IMG 數據 格式為 [[url,offw,offh],[url,offw,offh]]
i=0,//循環變量
j=0,//判斷當前的加載個數
warpper=document.getElementById('jelle_abcd'),//window,//容器對象
wf=(warpper==window) ? true : false;
doc={offw:0,offh:0,jtop:0,jleft:0},//包含一些 容器對象當前的一些屬性
sys=(function(){//不必緊張這只是一個判斷浏覽器的函數,你可以使用很多方法來判斷浏覽器
var ua=navigator.userAgent.toLowerCase(),sys={};
sys.firefox=ua.match(/firefox\/([\d\.]+)/);
sys.ie=ua.match(/msie\s([\d\.]+)/);
sys.chrome=ua.match(/chrome\/([\d\.]+)/);
return sys;
})(),
$j=function(id){return document.getElementById(id);},
imgall=$j('aaa').getElementsByTagName('DIV'),
getoff=function(o){//獲取IMG對象的 offw and offh
//alert(o.width)
o.innerHTML=(o.offsetTop-warpper.offsetTop) +','+ (o.offsetLeft-warpper.offsetLeft);
return (o.offsetTop-warpper.offsetTop) +','+ (o.offsetLeft-warpper.offsetLeft);
//注意 o.offsetTop 在chrome下要等window.onload以後才能正確獲取
};
//o.offsetTop獲取對象距離浏覽器頂部的距離 必須減去外面容器的距離浏覽器的距離。(如果使用window容器就不用了)
(function(){//初始化容器對象綁定事件==
if(wf){
window.onscroll=function(){_this.judge();};
window.onresize=function(){_this.judge();};
}else{
warpper.onscroll=function(){_this.judge();}
warpper.onresize=function(){_this.judge();}
}
window.onload=function(){setTimeout(_this.judge,500);};
})()
//容器對象設置結束
for( i ; i<imgall.length ; i++ ){//初始化imgs 數組
var arr=[],off;
off=getoff(imgall[i]);
//alert(off)
arr.push(imgsurl[0]);
arr.push((off.split(',')[0]));
arr.push((off.split(',')[1]));
imgs.push(arr);
}
_this.Load=function(){
var hereline=[];
hereline[1]=doc.offh+doc.jtop;
hereline[2]=doc.offw+doc.jleft;
for(i=0;i<imgs.length;i++){
if(imgs[i][1] != undefined){//判斷當前對象是否已經加載過
var jj=hereline[1] - imgs[i][1] < doc.offh +130 && hereline[1] - imgs[i][1] > 0 ? true : false,
jjj=hereline[2] - imgs[i][2] < doc.offw +270 && hereline[2] - imgs[i][2] > 0 ? true : false;
if(jj && jjj){
imgall[i].innerHTML+='第'+(++j)+'個加載';
imgs[i][1]=undefined;
}
}
}
if( j >= imgs.length){//判斷是否已經全部加載完畢
//取消時間綁定
alert("已經全部加載完成,程序將不再執行")
warpper.onscroll=null;
warpper.onresize=null;
}
}
_this.docInfo=function(){//獲取容器的相關信息
var d={},db= (wf)? document.body : warpper,
dd=(wf) ? document.documentElement : warpper;
if(sys.ie){
d.offh=dd.offsetHeight;//可視區域H
d.offw=dd.offsetWidth;//可視區域W
}else{
if(wf){
d.offw=window.innerWidth;//可視區域H
d.offh=window.innerHeight;//可視區域W
}else{
d.offh=dd.offsetHeight;//可視區域H
d.offw=dd.offsetWidth;//可視區域W
}
}
d.jtop=(wf) ? db.scrollTop+dd.scrollTop : db.scrollTop ;//垂直卷去高度
d.jleft=(wf) ? db.scrollLeft+dd.scrollLeft : db.scrollLeft;//水平卷去寬度
//被卷去的寬度 window 使用兩個相加 div的卷曲就直接使用scrollLeft就OK
$j("bbb").innerHTML=d.offh+','+d.offw+','+d.jtop+','+d.jleft
return d;
}
//注意在非IE 浏覽器下 獲取非window對象的可視區域 使用offsetHeight 和 offsetWidth (跟IE 一樣)
//在非IE 下獲取 window對象的可視區域 則要使用 window.innerWidth 和window.innerHeight
//也就是說在非IE 下的 window 和 非window 對象的 可視區域獲取是不一樣的。
_this.judge=function(){//後來發現不用判斷方向了
var d=_this.docInfo();
if( d.jtop != doc.jtop || d.jleft != doc.jleft || d.offw > doc.offw || d.offh > doc.offh){
//判斷是否需要執行加載
//條件為 被卷去的 y x 變化 或者 窗口大小 發生變化觸發
doc.jtop = d.jtop;
doc.offh = d.offh;
doc.jleft = d.jleft;
doc.offw = d.offw;
_this.Load();//加載程序
}
}
//setTimeout(_this.judge,500);//執行初始化加載
//setTimeout 防止onload 和 onscroll的重復執行
//也就是本來就有onscroll的時候 最先執行了onload
return _this;
}
})()
lazyload();
</script>
</body>
</html>
XML學習教程| jQuery入門知識| AJAX入門| Dreamweaver教程| Fireworks入門知識| SEO技巧| SEO優化集錦|
Copyright © DIV+CSS佈局教程網 All Rights Reserved