lazyload延迟加载组件
lazyload現(xiàn)在網(wǎng)上已經(jīng)用的很多(淘寶商城,新浪微博等等),先放demo:mylazyLoad.zip?
效果:
<div id="redbox1" οnclick="alert('js執(zhí)行了')" class="redbox">點(diǎn)擊我</div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div> <div class="redbox"></div> <div class="bluebox"></div>【基本原理】
在有大量數(shù)據(jù)加載的頁(yè)面中,我們需要一個(gè)容器,這個(gè)容器可以是瀏覽器窗口,也可以是頁(yè)面中的一個(gè)容器,在頁(yè)面加載的時(shí)候,我們可以將這容器顯示之外的內(nèi)容阻止其加載,當(dāng)我們滾動(dòng)這個(gè)容器到相應(yīng)區(qū)域的時(shí)候才將該區(qū)域內(nèi)容加載出來(lái),以此達(dá)到加快瀏覽速度的目的。
延遲加載一般分靜態(tài)和動(dòng)態(tài)兩種。
靜態(tài)的典型例子就是淘寶商城,我們?cè)谟^察淘寶商城的html時(shí)發(fā)現(xiàn),其頁(yè)面采用了大量的textarea來(lái)存放頁(yè)面元素,我們想要把頁(yè)面元素存放在html里,而又不想這些元素被解析,同時(shí)又能輕松方便的獲取,textarea正好滿足了這些條件(真不知道哪位牛人想到的)。
而動(dòng)態(tài)的可以說(shuō)就是ajax獲取數(shù)據(jù)再綁定,典型例子就是新浪微博,當(dāng)頁(yè)面滾動(dòng)到底部時(shí)觸發(fā)加載函數(shù)。
我的理解是將需要延遲加載的觸發(fā)元素存入一個(gè)數(shù)組中,當(dāng)容器scroll/resize時(shí)遍歷這個(gè)數(shù)組,如果觸發(fā)元素在視窗范圍內(nèi)就執(zhí)行加載函數(shù),并將這個(gè)元素從數(shù)組中刪除來(lái)提高效率。
【程序說(shuō)明】
一般在創(chuàng)建實(shí)例的時(shí)候,需要定義兩個(gè)屬性:elems和container,elems是觸發(fā)加載的元素集合,或者說(shuō)是加載內(nèi)容集合,container就是容器。
1.因?yàn)閑lems需要進(jìn)行刪除,所以首先需要將elems轉(zhuǎn)換為數(shù)組Array。
$A() code /*將參數(shù)轉(zhuǎn)換為數(shù)組?*?@param?{all}?a?參數(shù)
?*/
var?$A=function(a){
????if(!a)return?[];
????if(a?instanceof?Array)?return?a;
????var?arr=[],len=a.length;
????if(/string|number/.test(typeof?a)||a?instanceof?Function?||?len===undefined){
????????arr[0]=a;
????}else{
????????for(var?i=0;i<len;i++){
????????????arr[i]=a[i];
????????}
????}
????return?arr;????
}
this.elems=$A(this.options.elems);/*加載對(duì)象轉(zhuǎn)換成數(shù)組*/
參數(shù)a可以是string,number,object,array,function,HTMLCollection,null。
PS:我發(fā)現(xiàn)object.length===undefined
2.container是容器,可以是window,也可以是頁(yè)面元素,所以初始化時(shí)先判斷是否是window。
container var?doc=document;var?isWin?=?c==window||c==doc||c==null||!c.tagName||/body|html/i.test(c.tagName);/*判斷容器是否是window*/
if(isWin)c=doc.documentElement;
this.container=c;
如果不是明確的非body/html的dom元素,將都視為容器為window。
3.獲取container的顯示范圍,即容器相對(duì)于瀏覽器視窗左上角的top/bottom/left/right距離,如果是window,即瀏覽器視窗的大小。
getContainerRange /*獲取容器顯示范圍方法*/var?_getContainerRange=isWin&&window.innerWidth?function(){
????return?{top:0,left:0,right:window.innerWidth,bottom:window.innerHeight}
}:function(){
????return?_this._getRect(c);
}
this._refreshRange=function(){
????_this.range=_getContainerRange();
}
this._refreshRange();
/*獲取元素位置參數(shù)*/
_getRect:function(elem){
????var?r=elem.getBoundingClientRect();/*元素到窗口左上角距離*/
????return?{top:r.top,left:r.left,bottom:r.bottom,right:r.right}
}
?獲取瀏覽器視窗大小在IE下可以通過(guò)offsetWidth/offsetHeight獲得,但非IE瀏覽器則略有差異,好在非IE下有innerWidth/innerHeight可以使用。另外還有dom.getBoundingClientRect()這個(gè)方法,它的作用是獲得dom相對(duì)于視窗左上角的top/left/bottom/right距離,而且這個(gè)方法已經(jīng)得到所有瀏覽器的支持,大大提高了我們的效率。
PS:getBoundingClientRect可以看下http://www.cnblogs.com/qieqing/archive/2008/10/06/1304399.html?,另外談到IE下2px問(wèn)題,因?yàn)檫@里我都是用這個(gè)方法來(lái)獲取容器以及元素位置,所以這2px差異可以忽略,也許這不太嚴(yán)謹(jǐn),但同時(shí)也為了提高點(diǎn)效率考慮。
4.接下來(lái)就是給container綁定scroll/resize事件。
addEventHandler this._scrollload=function(){????if(!isWin){_this._refreshRange();}
????_this._doLoad();
}
this._noWinScroll=function(){?/*解決刷新時(shí)window滾動(dòng)條定位后造成range錯(cuò)誤bug*/
????_this.range=_getContainerRange();
????removeEventHandler(window,"scroll",_this._noWinScroll);
}
this._resizeload=function(){
????_this._refreshRange();
????_this._doLoad();
}
this.binder?=?isWin???window?:?c;
if(!isWin)addEventHandler(window,"scroll",this._noWinScroll);
addEventHandler(this.binder,"scroll",this._scrollload);
addEventHandler(this.binder,"resize",this._resizeload);
container是window話,scroll是不會(huì)改變container的range的,而container是元素的話,range會(huì)隨著window的scroll而改變,所以這里做分支處理。
另外當(dāng)我們講window的滾動(dòng)條滾至中間位置,再F5刷新頁(yè)面之后,滾動(dòng)條同樣會(huì)在剛剛的位置,IE下首先會(huì)將滾動(dòng)條提至頂部,再定位到剛剛的位置,這樣就出現(xiàn)了一個(gè)問(wèn)題,在第一次執(zhí)行l(wèi)azyload的時(shí)候,container的range是window滾動(dòng)條在頂部時(shí)候的值,而并非我們需要的實(shí)際值。所以我這里在非isWin情況下,給window綁定一次_noWinScroll事件,滾動(dòng)條定位后刪除這個(gè)事件。
5.下面講的是具體的判斷、執(zhí)行
_doLoad /*加載判斷,防止多次調(diào)用?@lock鎖定,加載過(guò)程中鎖定。如果為false,執(zhí)行加載;如果為true,延遲遞歸
*/
_doLoad:function(){
????var?_this=this;
????if(!this.lock){
????????this.lock=true;
????????setTimeout(function(){_this._loadRun()},100);
????}else{
????????clearTimeout(this.timer);
????????var?self=arguments.callee;
????????this.timer=setTimeout(function(){self.call(_this)},100);
????}
}
scroll事件在各個(gè)瀏覽器里的執(zhí)行次數(shù)不同,最好的是FF,一次滾輪滾動(dòng)只會(huì)執(zhí)行一次,而其他瀏覽器或多或少的會(huì)執(zhí)行多次。為了優(yōu)化這點(diǎn),用了一個(gè)lock判斷,當(dāng)在進(jìn)行加載函數(shù)_loadRun時(shí),我們鎖住scroll,具體方法就是"clearTimeout(this.timer);this.timer=setTimeout(function(){_this._doLoad();},100);",使用setTimeout延遲遞歸_doLoad,執(zhí)行第二次遞歸前clearTimeout上一次,這樣就能保證一次滾動(dòng)只執(zhí)行兩次,開(kāi)始一次,結(jié)束一次,中間的全部鎖住。
_loadRun /*加載運(yùn)行*/_loadRun:function(){
????var?elems=this.elems;
????if(elems.length){
????????for(var?i=0;i<elems.length;i++){
????????????var?rect=this._getRect(elems[i]);
????????????var?side=this._isRange(this._inRange(rect));
????????????if(side&&side!=0){
????????????????if(side==1&&!this.elock){
????????????????????this.elock=true;
????????????????????this._onDataLoad(elems[i]);
????????????????????elems.splice(i--,1);/*加載完之后將該對(duì)象從隊(duì)列中刪除*/
????????????????}else{break;}
????????????}
????????}????????????
????????if(!elems.length){
????????????this._release();
????????}
????}
????this.lock=false;
} _inRange:function(rect){
????var?range=this.range;
????var?side={
????????v?:?rect.top<=range.bottom???rect.bottom>=range.top???"in"?:?""?:?"bottom",/*垂直位置*/
????????h?:?rect.left<=range.right???rect.right>=range.left???"in"?:?""?:?"right"?/*水平位置*/
????};
????return?side;
},
_isRange:function(side){
????/*1:加載?-1:跳出循環(huán)?0:不加載執(zhí)行下一個(gè)*/
????return?{
????????v:side.v???side.v=="in"?1:-1?:?0,
????????h:side.h???side.h=="in"?1:-1?:?0,
????????c:side.v&&side.h???side.v=="in"&&side.h=="in"??1:side.v!="in"?-1:0?:?0
????}[this.mode||"c"]
}
這里的邏輯如下:
1)遍歷elems數(shù)組,獲取元素[0]的rect,根據(jù)rect和container的range做比較,判斷元素[0]相對(duì)于container的位置("[top/left]","bottom/right","in")
????????????????
2)再根據(jù)我們的mode獲得操作類(lèi)型(-1,0,1)。-1表示在容器顯示范圍的后面,之后的元素可以不再判斷,執(zhí)行跳出循環(huán);0表示在容器顯示范圍的前面,不執(zhí)行加載,進(jìn)行下個(gè)元素的判斷;1表示在顯示范圍內(nèi),需要加載。
3)當(dāng)返回的side為1時(shí),執(zhí)行_onDataLoad(),然后從元素集合中刪除該元素,用的方法是Array.splice(index,num),同時(shí)i--,使得能準(zhǔn)確的找到下個(gè)元素。這里的elock用來(lái)鎖定元素加載,主要用在動(dòng)態(tài)ajax加載的時(shí)候,因?yàn)閯?dòng)態(tài)加載的時(shí)候,我們希望當(dāng)多個(gè)元素同時(shí)存在于container以及多次觸發(fā)scroll時(shí),只執(zhí)行第一個(gè)元素的加載。
4)然后進(jìn)行下個(gè)元素[1]的判斷,重復(fù)之前的步驟。
5)當(dāng)元素集合為空時(shí),摧毀所有的綁定。
_release _release:function(){????removeEventHandler(this.binder,"scroll",this._scrollload);
????removeEventHandler(this.binder,"resize",this._resizeload);
????????this._onDataEnd();
}
6._onDataLoad默認(rèn)情況是靜態(tài)加載。
_onDataLoad /*刪除Script字符串內(nèi)容*/String.prototype.removeJS=function(){
????return?this.replace(/<script[^>]*?>([\w\W]*?)<\/script>/ig,"");
}
/*將Script字符串轉(zhuǎn)換為Script對(duì)象,返回Script?or?false*/
String.prototype.getJS=function(){
????var?js=this.replace(/[\s\S]*?<script[^>]*?>([\w\W]*?)<\/script>[\s\S]*?/g,"$1\r");
????if(js==this){
????????return?false;
????}else{
????????var?s=document.createElement("script");
????????s.text=js;
????????return?s;
????}
}
this._onDataLoad=this.options.ondataload?||?function(elem){?/*數(shù)據(jù)加載*/
????var?h=elem.getElementsByTagName("textarea");
????if(h.length){
????????var?js=h[0].value.getJS();?/*解決innerHTML?javascript不執(zhí)行的問(wèn)題*/
????????if(js){
????????????elem.innerHTML=h[0].value.removeJS();?/*刪除javascript字符串*/
????????????elem.appendChild(js);
????????}else{
????????????elem.innerHTML=h[0].value;
????????}
????}
????this.elock=false;
}
這里主要說(shuō)的是html里的javascript代碼問(wèn)題,通過(guò)innerHTML的javascript代碼是不會(huì)執(zhí)行的,所以在這里需要提取html里的script代碼,創(chuàng)建一個(gè)script元素,appendChild進(jìn)容器內(nèi)才能執(zhí)行。
【總結(jié)】
總的來(lái)說(shuō)在優(yōu)化上以及需求的考慮上都有了提高。也越來(lái)越喜歡用自己整理的框架去組件,這樣就能做到不僅知其然而且還能知其所以然。希望今后能在算法上得到指點(diǎn)。
demo丑了點(diǎn),大家湊合湊合(^。^)y-~~
【完整代碼】
javascript library //?JavaScript?Document/*my?javascript?library?v1.2*/
/*written?by?Lecaf*/
/*update?by?2011.4.12*/
/*刪除Script字符串內(nèi)容*/
String.prototype.removeJS=function(){
????return?this.replace(/<script[^>]*?>([\w\W]*?)<\/script>/ig,'');
}
/*將Script字符串轉(zhuǎn)換為Script對(duì)象,返回Script?or?false*/
String.prototype.getJS=function(){
????var?js=this.replace(/[\s\S]*?<script[^>]*?>([\w\W]*?)<\/script>[\s\S]*?/g,'$1\r');
????if(js==this){
????????return?false;
????}else{
????????var?s=document.createElement('script');
????????s.text=js;
????????return?s;
????}
}
/*getElementById
?*?@param?{String}?id?ID值
?*/
var?$id?=?function(id){
????if(typeof?id!='undefined'?&&?typeof?id?===?'string'){
????????return?document.getElementById(id);????
????}
????return?null;
}
/*講參數(shù)轉(zhuǎn)換為數(shù)組
?*?@param?{all}?a?參數(shù)
?*/
var?$A=function(a){
????if(!a)return?[];
????if(a?instanceof?Array)?return?a;
????var?arr=[],len=a.length;
????if(/string|number/.test(typeof?a)||a?instanceof?Function?||?len===undefined){
????????arr[0]=a;
????}else{
????????for(var?i=0;i<len;i++){
????????????arr[i]=a[i];
????????}
????}
????return?arr;????
}
/*注銷(xiāo)事件
?*?@param?{Object}?oTarget?對(duì)象
?*?@param?{String}?sEventType?事件類(lèi)型
?*?@param?{Function}?fnHandler?事件方法
?*/
var?removeEventHandler=function(oTarget,?sEventType,?fnHandler)?{
????if(oTarget.listeners[sEventType]){
????????var?listeners=oTarget.listeners[sEventType];
????????for(var?i=0,fn;fn=listeners[i++];){
????????????if(fn==fnHandler){
????????????????listeners.splice(--i,1);
????????????}
????????}
????????if(!listeners.length&&listeners["_handler"]){
????????????oTarget.removeEventListener???oTarget.removeEventListener(sEventType,?listeners["_handler"],?false)?:?oTarget.detachEvent('on'?+?sEventType,?listeners["_handler"]);
????????}
????}????
}
/*添加事件
?*?@param?{Object}?oTarget?對(duì)象
?*?@param?{String}?sEventType?事件類(lèi)型
?*?@param?{Function}?fnHandler?事件方法
?*/
var?addEventHandler=function(oTarget,?sEventType,?fnHandler)?{
????oTarget.listeners=oTarget.listeners||{};
????var?listeners?=?oTarget.listeners[sEventType]?=?oTarget.listeners[sEventType]||[];
????listeners.push(fnHandler);
????if(!listeners["_handler"]){
????????listeners["_handler"]=function(e){
????????????var?e=e||window.event;
????????????for(var?i=0,fn;fn=listeners[i++];){
????????????????fn.call(oTarget,e)
????????????}
????????}
????????oTarget.addEventListener???oTarget.addEventListener(sEventType,?listeners["_handler"],?false)?:?oTarget.attachEvent('on'?+?sEventType,?listeners["_handler"]);
????}????
}
/*觸發(fā)事件
?*?@param?{Object}?oTarget?對(duì)象
?*?@param?{String}?sEventType?事件類(lèi)型
?*/
var?dispatchEventHandler=function(oTarget,sEventType){
????if(oTarget.dispatchEvent){
????????var?e=document.createEvent('Event');
????????e.initEvent(sEventType,true,true);
????????oTarget.dispatchEvent(e);
????}else{
????????oTarget.fireEvent('on'+sEventType);
????}
}
/*json擴(kuò)展
?*?@param?{Object}?target?目標(biāo)json
?*?@param?{Object}?src?源json
?*/
var?extendJson=function(target,src){
????for(var?para?in?src){
????????target[para]=src[para];
????}
????return?target;
}
/*在目標(biāo)元素之后插入新元素?js自帶方法:?target.appendChild(newDoc);target.insertBefore(newDoc,existingChild);
?*?@param?{Document}?newEl?新元素
?*?@param?{Document}?targetEl?目標(biāo)元素
?*/
var?insertAfter=function(newEl,targetEl){
????var?parentEl?=?targetEl.parentNode;
????if(parentEl.lastChild?==?targetEl){
????????parentEl.appendChild(newEl);
????}else{
????????parentEl.insertBefore(newEl,targetEl.nextSibling);
????}
}
/*動(dòng)態(tài)加載CSS文件
?*?@param?{String}?file?css路徑
?*?@param?{String}?cssid?css?link?ID
?*/
var?loadCSS=function?(file,cssid){
????var?cssTag?=?cssid???document.getElementById(cssid)?:?null;
????var?head?=?document.getElementsByTagName('head').item(0);
????if(cssTag)?head.removeChild(cssTag);
????css?=?document.createElement('link');
????css.href?=?file;
????css.rel?=?'stylesheet';
????css.type?=?'text/css';
????if(cssid){css.id?=?cssid;}
????head.appendChild(css);
}
/*ajax封裝
?*?@param?{Object}?options?參數(shù)集
?*?@param?{String}?url?鏈接
?*?@param?{String}?type?傳參方式?'POST'?or?'GET'(默認(rèn))
?*?@param?{Bool}?async?是否異步?true異步(默認(rèn))?false同步
?*?@param?{String}?dataType?返回?cái)?shù)據(jù)類(lèi)型?'html'(默認(rèn))?'xml'?'json'
?*?@param?{Function}?beforeSend?發(fā)送請(qǐng)求前調(diào)用函數(shù)
?*?@param?{Function}?success?請(qǐng)求成功后回調(diào)函數(shù)
?*?@param?{Function}?complete?請(qǐng)求完成后回調(diào)函數(shù)(不管成功與否)
?*/
var?ajaxFun?=?function(options){
????var?ajaxops={
????????url:'',
????????type:'GET',
????????async:true,
????????dataType:'html',
????????beforeSend:null,
????????success:function(){},
????????complete:null
????}
????var?ajaxops?=?extendJson(ajaxops,options);
????if(ajaxops.url){
????????var?xmlHttp;
????
????????try{
????????????//?Firefox,?Opera?8.0+,?Safari
????????????xmlHttp=new?XMLHttpRequest();
????????}catch?(e){
????????????//?Internet?Explorer
????????????try{
????????????????xmlHttp=new?ActiveXObject('Msxml2.XMLHTTP');
????????????}catch?(e){
????????????????try{
????????????????????xmlHttp=new?ActiveXObject('Microsoft.XMLHTTP');
????????????????}catch?(e){
????????????????????alert('您的瀏覽器不支持AJAX!');
????????????????????return?false;
????????????????}
????????????}
????????}
????????var?requestDone=false;
????????
????????if(!ajaxops.async&&navigator.userAgent.indexOf('Firefox')>0){
????????????xmlHttp.onload=function(){
????????????????if((?xmlHttp.status?>=?200?&&?xmlHttp.status?<?300?)?||?xmlHttp.status?===?304?||?xmlHttp.status?===?1223?||?xmlHttp.status?===?0){
????????????????????var?msg;
????????????????????switch(ajaxops.dataType){
????????????????????????case?'html':
????????????????????????????msg=xmlHttp.responseText;
????????????????????????????break;
????????????????????????case?'xml':
????????????????????????????msg=xmlHttp.responseXML;
????????????????????????????break;
????????????????????????case?'json':
????????????????????????????msg=xmlHttp.responseText;
????????????????????????????msg=(new?Function('return?'+msg))();
????????????????????????????break;
????????????????????????default:
????????????????????????????msg=xmlHttp.responseText;
????????????????????????????break;
????????????????????}
????????????????????ajaxops.success(msg);
????????????????}
????????????????if(ajaxops.complete?&&?!requestDone){
????????????????????ajaxops.complete(msg);
????????????????????requestDone=true;
????????????????}
????????????}
????????}else{
????????????xmlHttp.onreadystatechange=function(){????????
????????????????if(xmlHttp.readyState===4){
????????????????????if((?xmlHttp.status?>=?200?&&?xmlHttp.status?<?300?)?||?xmlHttp.status?===?304?||?xmlHttp.status?===?1223?||?xmlHttp.status?===?0){
????????????????????????var?msg;
????????????????????????switch(ajaxops.dataType){
????????????????????????????case?'html':
????????????????????????????????msg=xmlHttp.responseText;
????????????????????????????????break;
????????????????????????????case?'xml':
????????????????????????????????msg=xmlHttp.responseXML;
????????????????????????????????break;
????????????????????????????case?'json':
????????????????????????????????msg=xmlHttp.responseText;
????????????????????????????????msg=(new?Function('return?'+msg))();
????????????????????????????????break;
????????????????????????????default:
????????????????????????????????msg=xmlHttp.responseText;
????????????????????????????????break;
????????????????????????}
????????????????????????ajaxops.success(msg);
????????????????????}
????????????????????if(ajaxops.complete?&&?!requestDone){
????????????????????????ajaxops.complete(msg);
????????????????????????requestDone=true;
????????????????????}
????????????????}
????????????}
????????}
????????if(ajaxops.beforeSend){
????????????ajaxops.beforeSend();
????????}
????????xmlHttp.open(ajaxops.type,ajaxops.url,ajaxops.async);
????????xmlHttp.send(null);
????}
}
/*
?*?$class?寫(xiě)類(lèi)工具函數(shù)
?*?@param?{Function}?constructor
?*?@param?{Object}?prototype
?*?write?by?Snandy?http://www.cnblogs.com/snandy/
?*/
var?$class?=?function(constructor,prototype)?{
????var?c?=?constructor?||?function(){};
????var?p?=?prototype?||?{};
????return?function()?{????????
????????for(var?atr?in?p)?{
????????????arguments.callee.prototype[atr]?=?p[atr];
????????}????????????
????????c.apply(this,arguments);
????}
} lazyload //?JavaScript?Document
/*Lazyload?v1.2*/
/*written?by?Lecaf*/
/*update?by?2011.4.8*/
var?Lazyload=function(options){
????this._init(options);/*初始化*/
????this._doLoad();/*第一次加載*/
????if(!this.elems.length)this._release();/*如果加載元素為空,釋放*/
}
var?proto={
????/*初始化參數(shù)*/
????_init:function(options){
????????this.binder=null;?/*加載容器對(duì)象*/
????????this.range={};?/*加載容器顯示范圍*/
????????this.elems=[];/*加載對(duì)象隊(duì)列*/
????????this.container=null;
????????this.mode="";
????????this.lock=false;/*加載容器鎖定*/
????????this.elock=false;/*加載元素鎖定*/
????????this.timer=null;/*_doLoad計(jì)時(shí)器*/
????????this.options={?/*定制參數(shù)*/
????????????container:window,/*加載容器*/
????????????elems:null,/*加載數(shù)據(jù)集合*/
????????????mode:"v",/*加載模式?v(垂直加載)?h(水平加載)?c(交叉加載)?默認(rèn)v*/
????????????ondataload:null,/*數(shù)據(jù)加載方式*/
????????????ondataend:function(){}/*數(shù)據(jù)加載完畢*/
????????}
????????extendJson(this.options,options||{});
????????this.elems=$A(this.options.elems);/*加載對(duì)象轉(zhuǎn)換成數(shù)組*/
????????this.mode=this.options.mode;
????????this._onDataLoad=this.options.ondataload?||?function(elem){?/*數(shù)據(jù)加載*/
????????????var?h=elem.getElementsByTagName("textarea");
????????????if(h.length){
????????????????var?js=h[0].value.getJS();?/*解決innerHTML?javascript不執(zhí)行的問(wèn)題*/
????????????????if(js){
????????????????????elem.innerHTML=h[0].value.removeJS();?/*刪除javascript字符串*/
????????????????????elem.appendChild(js);
????????????????}else{
????????????????????elem.innerHTML=h[0].value;
????????????????}
????????????}
????????????this.elock=false;
????????}
????????this._onDataEnd=this.options.ondataend;?/*所有內(nèi)容加載完執(zhí)行*/
????????this._initContainer(this.options.container);/*初始化容器*/
????},
????/*初始化容器*/
????_initContainer:function(c){
????????var?doc=document;
????????var?_this=this;
????????var?isWin?=?c==window||c==doc||c==null||!c.tagName||/body|html/i.test(c.tagName);/*判斷容器是否是window*/
????????if(isWin)c=doc.documentElement;
????????this.container=c;
????????/*獲取容器顯示范圍方法*/
????????var?_getContainerRange=isWin&&window.innerWidth?function(){
????????????return?{top:0,left:0,right:window.innerWidth,bottom:window.innerHeight}
????????}:function(){
????????????return?_this._getRect(c);
????????}
????????this._refreshRange=function(){
????????????_this.range=_getContainerRange();
????????}
????????this._refreshRange();
????????this._scrollload=function(){
????????????if(!isWin){_this._refreshRange();}
????????????_this._doLoad();
????????}
????????this._noWinScroll=function(){?/*解決刷新時(shí)window滾動(dòng)條定位后造成range錯(cuò)誤bug*/
????????????_this.range=_getContainerRange();
????????????removeEventHandler(window,"scroll",_this._noWinScroll);
????????}
????????this._resizeload=function(){
????????????_this._refreshRange();
????????????_this._doLoad();
????????}
????????this.binder?=?isWin???window?:?c;
????????if(!isWin)addEventHandler(window,"scroll",this._noWinScroll);
????????addEventHandler(this.binder,"scroll",this._scrollload);
????????addEventHandler(this.binder,"resize",this._resizeload);
????},
????/*獲取元素位置參數(shù)*/
????_getRect:function(elem){
????????var?r=elem.getBoundingClientRect();/*元素到窗口左上角距離*/
????????return?{top:r.top,left:r.left,bottom:r.bottom,right:r.right}
????},
????/*加載判斷,防止多次調(diào)用
?????@lock鎖定,加載過(guò)程中鎖定。如果為false,執(zhí)行加載;如果為true,延遲遞歸
????*/
????_doLoad:function(){
????????var?_this=this;
????????if(!this.lock){
????????????this.lock=true;
????????????setTimeout(function(){_this._loadRun()},100);
????????}else{
????????????clearTimeout(this.timer);
????????????var?self=arguments.callee;
????????????this.timer=setTimeout(function(){self.call(_this)},100);
????????}
????},
????/*加載運(yùn)行*/
????_loadRun:function(){
????????var?elems=this.elems;
????????if(elems.length){
????????????for(var?i=0;i<elems.length;i++){
????????????????var?rect=this._getRect(elems[i]);
????????????????var?side=this._isRange(this._inRange(rect));
????????????????if(side&&side!=0){
????????????????????if(side==1&&!this.elock){
????????????????????????this.elock=true;
????????????????????????this._onDataLoad(elems[i]);
????????????????????????elems.splice(i--,1);/*加載完之后將該對(duì)象從隊(duì)列中刪除*/
????????????????????}else{break;}
????????????????}
????????????}????????????
????????????if(!elems.length){
????????????????this._release();
????????????}
????????}
????????this.lock=false;
????},
????/*判斷對(duì)象相對(duì)容器位置*/
????_inRange:function(rect){
????????var?range=this.range;
????????var?side={
????????????v?:?rect.top<=range.bottom???rect.bottom>=range.top???"in"?:?""?:?"bottom",/*垂直位置*/
????????????h?:?rect.left<=range.right???rect.right>=range.left???"in"?:?""?:?"right"?/*水平位置*/
????????};
????????return?side;
????},
????_isRange:function(side){
????????/*1:加載?-1:跳出循環(huán)?0:不加載執(zhí)行下一個(gè)*/
????????return?{
????????????v:side.v???side.v=="in"?1:-1?:?0,
????????????h:side.h???side.h=="in"?1:-1?:?0,
????????????c:side.v&&side.h???side.v=="in"&&side.h=="in"??1:side.v!="in"?-1:0?:?0
????????}[this.mode||"c"]
????},
????/*釋放*/
????_release:function(){
????????removeEventHandler(this.binder,"scroll",this._scrollload);
????????removeEventHandler(this.binder,"resize",this._resizeload);
????????this._onDataEnd();
????}
}
window.onload=function(){
????var?Divload=$class(Lazyload,proto);
????var?divload=new?Divload({
????????elems:document.getElementById("loadmain").getElementsByTagName("div"),
????????container:$id("loadbox"),
????????mode:"c"
????});
????var?Winload=$class(Lazyload,proto);
????var?winload=new?Winload({
????????elems:$id("ajaxbox").getElementsByTagName("div"),
????????container:window,
????????ondataload:function(elem){????????
????????????var?othis=this;
????????????ajaxFun({
????????????????url:"ajax.html",
????????????????beforeSend:function(){
????????????????????elem.getElementsByTagName("p")[0].style.display="";
????????????????},
????????????????success:function(msg){
????????????????????var?box=document.getElementById("ajaxload");
????????????????????box.innerHTML=box.innerHTML+msg;
????????????????},
????????????????complete:function(){
????????????????????othis.elock=false;
????????????????}
????????????})
????????}
????})
}
轉(zhuǎn)載于:https://www.cnblogs.com/lecaf/archive/2011/04/08/lazyload.html
總結(jié)
以上是生活随笔為你收集整理的lazyload延迟加载组件的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 允许修改 SharePoint2010
- 下一篇: 备忘: 网络订购烟草