【分享】LazyLoad延迟加载(按需加载)

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:我的源码

 

ContractedBlock.gifExpandedBlockStart.gif代码
<!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>

转载于:https://www.cnblogs.com/idche/archive/2010/05/27/lazyload.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/261958.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python中ipo模型有_python ipo模型是指什么?_后端开发

c语言中如何用do...while语句求1到100的累加和_后端开发 c语言中用do...while语句求1到100的累加和的方法是&#xff1a;1、首先定义变量i与sum&#xff0c;如【int sum0,i1】&#xff1b;2、然后用do...while语句实现即可&#xff0c;如【do{sumsumi;i;}while(i<100)】。py…

英语26个字母使用频度

LetterLetter namePronunciation NLetterFrequency LetterFrequencyAa/ˈeɪ/, //[nb 2] 1A8.17% E12.70%Bbee/ˈbiː/ 2B1.49% T9.06%Ccee/ˈsiː/ 3C2.78% A8.17%Ddee/ˈdiː/ 4D4.25% O7.51%Ee/ˈiː/ 5E12.70% I6.97%Fef (eff as a verb)/ˈɛf/ 6F2.23% N6.75%Ggee/ˈdʒi…

java签到_实战:如果让你用SpringBoot实现签到奖励的功能,你会怎么做?

阅读本文大概需要 6 分钟。来自&#xff1a;网络前言最近在做社交业务&#xff0c;用户进入APP后有签到功能&#xff0c;签到成功后获取相应的奖励&#xff1a;项目状况&#xff1a;前期尝试业务阶段&#xff1b;特点&#xff1a;快速实现&#xff08;不需要做太重&#xff0c;…

软件开发工具介绍之 1.代码生成器

在程序开发过程当中&#xff0c;程序员会经常做着重复性的工作&#xff0c;最常见的是访问数据库&#xff0c;程序员要经常编写增、删、改、分页之类的操作。为了避免这个问题&#xff0c;节省大量机械录入的时间和重复劳动&#xff0c;提高工作效率&#xff0c;而将精力集中于…

python自带的shell、其性能优于ipython吗_Python自带的shell,其性能优于IPython

信源X的&#xff0c;自带每一机事件的都相等个随概率&#xff0c;即P。 优于 自带优于 自带求(机械的保养要。 优于标有机械的主管理要指。 下尺性期人手节分的病离急法整复后&#xff0c;自带项处做哪理&#xff1a;还应。 并放下肢射至&#xff0c;优于现右肢放扭伤右下臀及后…

虚拟机测试必备虚拟机之VirtualBox 使用

2019独角兽企业重金招聘Python工程师标准>>> 安装&#xff0c;windowns在官网上对应版本下载下一步安装结束即可&#xff0c;配置有seting可以选择中文&#xff0c;方便理解&#xff0c;其实英文也好功能 不多。 安装linux&#xff1a;ubuntu&#xff0c;如果有网su…

基于.NET Framework 4.0的解决方案部署

VS 2010发布之后&#xff0c;随着而来的框架版本也升级到了.NET Framework 4.0。我相信很多朋友已经在用了吧。这一篇文章总结了如何基于.NET Framework 4.0&#xff0c;进行解决方案部署。 之所以要单独写一下&#xff0c;是因为确实这个版本与之前的.NET Framework 2.0&#…

如何在Windows Azure VM上的SQL Server和Windows Azure SQL Database两者中做出选择

作者信息&#xff1a;本篇文章是由SQL Server Cloud Infrastructure Team的 Madhan Arumugam 和 Guy Bowerman共同著作。 简介 把SQL 数据托管在哪里&#xff0c;Windows Azure 为您提供了两个选择&#xff0c;VM上的SQL Server&#xff08;以下简称 SQL/VM&#xff09;和 Wind…

graphviz 画决策树_数据挖掘入门系列教程(四)之基于scikit-lean决策树处理Iris

数据挖掘入门系列教程&#xff08;四&#xff09;之基于scikit-lean决策树处理Iris加载数据集数据特征训练随机森林调参工程师结尾数据挖掘入门系列教程&#xff08;四&#xff09;之基于scikit-lean决策树处理Iris在上一篇博客&#xff0c;我们介绍了决策树的一些知识。如果对…

设计模式UML图

1.简单工厂模式 2.工厂模式 工厂模式与简单工厂模式的不同在于&#xff0c;每个操作类都有自己的工厂&#xff0c;而且把逻辑判断交给了客户端&#xff0c;而简单工厂的逻辑判断在工厂类里边&#xff0c;当增加新的操作类时&#xff0c;简单工厂需要修改工厂类&#xff0c;而工…

Android小項目之--ListView與ListAcitivity完善論壇管理效果2(附源碼)

ListAcitivity 类型布局用来配置应用程序&#xff0c;主要为显示菜单列表、列表明细项目&#xff0c;假如让程序继承 ListActivity ,可以实现以下的方法&#xff1a; getListAdapter()  取得目前列表项目的 AdaptergetListView()  取得目前列表的 ViewgetSelectedItemId() …

docker 覆盖 entrypoint_最佳实践,Dockerfile中ENTRYPOINT与CMD指令的区别与建议

通过本文你会获得什么熟悉Dockerfile中ENTRYPOINT和CMD指令之间的区别&#xff0c;以及在实际项目中的使用建议。1 - 开始前准备首先你要有个docker环境&#xff0c;以下实验基于&#xff1a;docker 18.09&#xff0c;以及alpine:3.8镜像。下载基础镜像docker pull alpine:3.82…

单实例单向rac搭建gg流

1、 m1 m2 m3 source端 2、 在m1 m2 m3 上 /etc/hosts 172.16.10.140 source source上 添加 #public network 172.16.15.101 m1 172.16.15.102 m2 172.16.15.103 m3 #private network 10.11.11.1 m1-pri 10.11.11.2 m2-pri 10.11.11.3 m3-pri 29 #VIP network 172.16.15.1…

python自动登录教程_Python 实现自动登录+点击+滑动验证功能

需要用到的库有selenium&#xff0c;还需要安装Chrome浏览器驱动&#xff0c;具体如何安装我就不详述了 在这里我模拟了csdn的登录过程 ** 1**.首先打开网页&#xff0c;用户名密码登录&#xff0c;然后定位用户名输入框&#xff0c;和密码输入框&#xff0c;输入后 点击登陆 弹…

2月份.xyz域名总量10强:西数称王 注册量破百万

IDC评述网&#xff08;idcps.com&#xff09;02月25日报道&#xff1a;根据ntldstats.com发布的最新数据显示&#xff0c;截止至2016年2月24日17时&#xff0c;国内外.xyz域名总量十强名单顺序&#xff0c;与上期1月28日对比&#xff0c;无任何变化。最值得一提的是&#xff0c…

flash作业_一起作业,你很智障!

电子作业现在貌似很流行&#xff0c;在很多学校都有&#xff0c;具体的利弊就不再赘述&#xff0c;可以点击前面的超链接跳转到某度百科自己看。今天只是忍不住怕盘点下国内知名电子作业平台——一起作业网的一些智障设计。。。本来想写到这里去的&#xff1a;有哪些让人拍案叫…

QtCreator添加图片资源

在qt creator里面&#xff0c;设计师designer是一个很好用的功能&#xff0c;通过它我们可以可视化的设计界面。当然了&#xff0c;设计界面就需要各种各样的效果&#xff0c;图片资源是不可少的。今天&#xff0c;小编就来教大家qt怎么添加图片资源 工具/原料 qt creator方法/…

只安装python_AI帮你写Python,安装只需5步,还能任你调教 | 开源

一行一行地敲代码就像是徒手搬砖&#xff0c;聪明的程序猿们表示&#xff1a;我们要解放生产力&#xff01; 比如像这样&#xff1a;在机器学习的时代&#xff0c;AI智能补全代码早已不是梦想&#xff0c;各种IDE和插件都在努力帮助程序猿减少击键次数&#xff0c;延长键盘寿命…

巧用apply让javascript函数仅执行一次

RT,有时候我们只想要让某些脚步函数执行一次就算完成任务了。如何实现这种功能呢&#xff1f;简单模仿下面这段就可以轻松搞定了&#xff1a; 代码 varobj newObject();obj.triggerOnce function(fn) { //控制让函数只触发一次returnfunction() { try{ fn.ap…

评论时间戳格式化

如图&#xff1a; 注意&#xff0c;评论时间戳的格式&#xff0c;刚才&#xff0c;几小时之前&#xff0c;几天之前..... 实现需要一个时间格式的工具类&#xff0c;如果用java.util.Date当然也可以实现&#xff0c;这里说的是更方便的joda-time。 maven地址&#xff1a;http:/…