lazyload延迟加载组件
lazyload現在網上已經用的很多(淘寶商城,新浪微博等等),先放demo:mylazyLoad.zip?
效果:
<div id="redbox1" οnclick="alert('js執行了')" 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> <div class="redbox"></div> <div class="bluebox"></div>【基本原理】
在有大量數據加載的頁面中,我們需要一個容器,這個容器可以是瀏覽器窗口,也可以是頁面中的一個容器,在頁面加載的時候,我們可以將這容器顯示之外的內容阻止其加載,當我們滾動這個容器到相應區域的時候才將該區域內容加載出來,以此達到加快瀏覽速度的目的。
延遲加載一般分靜態和動態兩種。
靜態的典型例子就是淘寶商城,我們在觀察淘寶商城的html時發現,其頁面采用了大量的textarea來存放頁面元素,我們想要把頁面元素存放在html里,而又不想這些元素被解析,同時又能輕松方便的獲取,textarea正好滿足了這些條件(真不知道哪位牛人想到的)。
而動態的可以說就是ajax獲取數據再綁定,典型例子就是新浪微博,當頁面滾動到底部時觸發加載函數。
我的理解是將需要延遲加載的觸發元素存入一個數組中,當容器scroll/resize時遍歷這個數組,如果觸發元素在視窗范圍內就執行加載函數,并將這個元素從數組中刪除來提高效率。
【程序說明】
一般在創建實例的時候,需要定義兩個屬性:elems和container,elems是觸發加載的元素集合,或者說是加載內容集合,container就是容器。
1.因為elems需要進行刪除,所以首先需要將elems轉換為數組Array。
$A() code /*將參數轉換為數組?*?@param?{all}?a?參數
?*/
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);/*加載對象轉換成數組*/
參數a可以是string,number,object,array,function,HTMLCollection,null。
PS:我發現object.length===undefined
2.container是容器,可以是window,也可以是頁面元素,所以初始化時先判斷是否是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的顯示范圍,即容器相對于瀏覽器視窗左上角的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();
/*獲取元素位置參數*/
_getRect:function(elem){
????var?r=elem.getBoundingClientRect();/*元素到窗口左上角距離*/
????return?{top:r.top,left:r.left,bottom:r.bottom,right:r.right}
}
?獲取瀏覽器視窗大小在IE下可以通過offsetWidth/offsetHeight獲得,但非IE瀏覽器則略有差異,好在非IE下有innerWidth/innerHeight可以使用。另外還有dom.getBoundingClientRect()這個方法,它的作用是獲得dom相對于視窗左上角的top/left/bottom/right距離,而且這個方法已經得到所有瀏覽器的支持,大大提高了我們的效率。
PS:getBoundingClientRect可以看下http://www.cnblogs.com/qieqing/archive/2008/10/06/1304399.html?,另外談到IE下2px問題,因為這里我都是用這個方法來獲取容器以及元素位置,所以這2px差異可以忽略,也許這不太嚴謹,但同時也為了提高點效率考慮。
4.接下來就是給container綁定scroll/resize事件。
addEventHandler this._scrollload=function(){????if(!isWin){_this._refreshRange();}
????_this._doLoad();
}
this._noWinScroll=function(){?/*解決刷新時window滾動條定位后造成range錯誤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是不會改變container的range的,而container是元素的話,range會隨著window的scroll而改變,所以這里做分支處理。
另外當我們講window的滾動條滾至中間位置,再F5刷新頁面之后,滾動條同樣會在剛剛的位置,IE下首先會將滾動條提至頂部,再定位到剛剛的位置,這樣就出現了一個問題,在第一次執行lazyload的時候,container的range是window滾動條在頂部時候的值,而并非我們需要的實際值。所以我這里在非isWin情況下,給window綁定一次_noWinScroll事件,滾動條定位后刪除這個事件。
5.下面講的是具體的判斷、執行
_doLoad /*加載判斷,防止多次調用?@lock鎖定,加載過程中鎖定。如果為false,執行加載;如果為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事件在各個瀏覽器里的執行次數不同,最好的是FF,一次滾輪滾動只會執行一次,而其他瀏覽器或多或少的會執行多次。為了優化這點,用了一個lock判斷,當在進行加載函數_loadRun時,我們鎖住scroll,具體方法就是"clearTimeout(this.timer);this.timer=setTimeout(function(){_this._doLoad();},100);",使用setTimeout延遲遞歸_doLoad,執行第二次遞歸前clearTimeout上一次,這樣就能保證一次滾動只執行兩次,開始一次,結束一次,中間的全部鎖住。
_loadRun /*加載運行*/_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);/*加載完之后將該對象從隊列中刪除*/
????????????????}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:跳出循環?0:不加載執行下一個*/
????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數組,獲取元素[0]的rect,根據rect和container的range做比較,判斷元素[0]相對于container的位置("[top/left]","bottom/right","in")
????????????????
2)再根據我們的mode獲得操作類型(-1,0,1)。-1表示在容器顯示范圍的后面,之后的元素可以不再判斷,執行跳出循環;0表示在容器顯示范圍的前面,不執行加載,進行下個元素的判斷;1表示在顯示范圍內,需要加載。
3)當返回的side為1時,執行_onDataLoad(),然后從元素集合中刪除該元素,用的方法是Array.splice(index,num),同時i--,使得能準確的找到下個元素。這里的elock用來鎖定元素加載,主要用在動態ajax加載的時候,因為動態加載的時候,我們希望當多個元素同時存在于container以及多次觸發scroll時,只執行第一個元素的加載。
4)然后進行下個元素[1]的判斷,重復之前的步驟。
5)當元素集合為空時,摧毀所有的綁定。
_release _release:function(){????removeEventHandler(this.binder,"scroll",this._scrollload);
????removeEventHandler(this.binder,"resize",this._resizeload);
????????this._onDataEnd();
}
6._onDataLoad默認情況是靜態加載。
_onDataLoad /*刪除Script字符串內容*/String.prototype.removeJS=function(){
????return?this.replace(/<script[^>]*?>([\w\W]*?)<\/script>/ig,"");
}
/*將Script字符串轉換為Script對象,返回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){?/*數據加載*/
????var?h=elem.getElementsByTagName("textarea");
????if(h.length){
????????var?js=h[0].value.getJS();?/*解決innerHTML?javascript不執行的問題*/
????????if(js){
????????????elem.innerHTML=h[0].value.removeJS();?/*刪除javascript字符串*/
????????????elem.appendChild(js);
????????}else{
????????????elem.innerHTML=h[0].value;
????????}
????}
????this.elock=false;
}
這里主要說的是html里的javascript代碼問題,通過innerHTML的javascript代碼是不會執行的,所以在這里需要提取html里的script代碼,創建一個script元素,appendChild進容器內才能執行。
【總結】
總的來說在優化上以及需求的考慮上都有了提高。也越來越喜歡用自己整理的框架去組件,這樣就能做到不僅知其然而且還能知其所以然。希望今后能在算法上得到指點。
demo丑了點,大家湊合湊合(^。^)y-~~
【完整代碼】
javascript library //?JavaScript?Document/*my?javascript?library?v1.2*/
/*written?by?Lecaf*/
/*update?by?2011.4.12*/
/*刪除Script字符串內容*/
String.prototype.removeJS=function(){
????return?this.replace(/<script[^>]*?>([\w\W]*?)<\/script>/ig,'');
}
/*將Script字符串轉換為Script對象,返回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;
}
/*講參數轉換為數組
?*?@param?{all}?a?參數
?*/
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;????
}
/*注銷事件
?*?@param?{Object}?oTarget?對象
?*?@param?{String}?sEventType?事件類型
?*?@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?對象
?*?@param?{String}?sEventType?事件類型
?*?@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"]);
????}????
}
/*觸發事件
?*?@param?{Object}?oTarget?對象
?*?@param?{String}?sEventType?事件類型
?*/
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擴展
?*?@param?{Object}?target?目標json
?*?@param?{Object}?src?源json
?*/
var?extendJson=function(target,src){
????for(var?para?in?src){
????????target[para]=src[para];
????}
????return?target;
}
/*在目標元素之后插入新元素?js自帶方法:?target.appendChild(newDoc);target.insertBefore(newDoc,existingChild);
?*?@param?{Document}?newEl?新元素
?*?@param?{Document}?targetEl?目標元素
?*/
var?insertAfter=function(newEl,targetEl){
????var?parentEl?=?targetEl.parentNode;
????if(parentEl.lastChild?==?targetEl){
????????parentEl.appendChild(newEl);
????}else{
????????parentEl.insertBefore(newEl,targetEl.nextSibling);
????}
}
/*動態加載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?參數集
?*?@param?{String}?url?鏈接
?*?@param?{String}?type?傳參方式?'POST'?or?'GET'(默認)
?*?@param?{Bool}?async?是否異步?true異步(默認)?false同步
?*?@param?{String}?dataType?返回數據類型?'html'(默認)?'xml'?'json'
?*?@param?{Function}?beforeSend?發送請求前調用函數
?*?@param?{Function}?success?請求成功后回調函數
?*?@param?{Function}?complete?請求完成后回調函數(不管成功與否)
?*/
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?寫類工具函數
?*?@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={
????/*初始化參數*/
????_init:function(options){
????????this.binder=null;?/*加載容器對象*/
????????this.range={};?/*加載容器顯示范圍*/
????????this.elems=[];/*加載對象隊列*/
????????this.container=null;
????????this.mode="";
????????this.lock=false;/*加載容器鎖定*/
????????this.elock=false;/*加載元素鎖定*/
????????this.timer=null;/*_doLoad計時器*/
????????this.options={?/*定制參數*/
????????????container:window,/*加載容器*/
????????????elems:null,/*加載數據集合*/
????????????mode:"v",/*加載模式?v(垂直加載)?h(水平加載)?c(交叉加載)?默認v*/
????????????ondataload:null,/*數據加載方式*/
????????????ondataend:function(){}/*數據加載完畢*/
????????}
????????extendJson(this.options,options||{});
????????this.elems=$A(this.options.elems);/*加載對象轉換成數組*/
????????this.mode=this.options.mode;
????????this._onDataLoad=this.options.ondataload?||?function(elem){?/*數據加載*/
????????????var?h=elem.getElementsByTagName("textarea");
????????????if(h.length){
????????????????var?js=h[0].value.getJS();?/*解決innerHTML?javascript不執行的問題*/
????????????????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;?/*所有內容加載完執行*/
????????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(){?/*解決刷新時window滾動條定位后造成range錯誤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);
????},
????/*獲取元素位置參數*/
????_getRect:function(elem){
????????var?r=elem.getBoundingClientRect();/*元素到窗口左上角距離*/
????????return?{top:r.top,left:r.left,bottom:r.bottom,right:r.right}
????},
????/*加載判斷,防止多次調用
?????@lock鎖定,加載過程中鎖定。如果為false,執行加載;如果為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);
????????}
????},
????/*加載運行*/
????_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);/*加載完之后將該對象從隊列中刪除*/
????????????????????}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:跳出循環?0:不加載執行下一個*/
????????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;
????????????????}
????????????})
????????}
????})
}
轉載于:https://www.cnblogs.com/lecaf/archive/2011/04/08/lazyload.html
總結
以上是生活随笔為你收集整理的lazyload延迟加载组件的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 允许修改 SharePoint2010
- 下一篇: 【翻译】HTML5基于浏览器的媒体播放器