jquery lazyload延迟加载技术的实现原理分析


Posted in Javascript onJanuary 24, 2011

前言

懒加载技术(简称lazyload)并不是新技术,它是js程序员对网页性能优化的一种方案。lazyload的核心是按需加载。在大型网站中都有lazyload的身影,例如谷歌的图片搜索页,迅雷首页,淘宝网,QQ空间等。因此掌握lazyload技术是个不错的选择,可惜jquery插件lazy load官网(http://www.appelsiini.net/projects/lazyload)称不支持新版浏览器。

lazyload在什么场合中应用比较合适?

涉及到图片,falsh资源,iframe,网页编辑器(类似FCK)等占用较大带宽,且这些模块暂且不在浏览器可视区内,因此可以使用lazyload在适当的时候加载该类资源。避免网页打开时加载过多资源,让用户等待太久。

如何实现lazyload?

lazyload的难点在如何在适当的时候加载用户需要的资源(这里用户需要的资源指该资源呈现在浏览器可视区域)。因此我们需要知道几点信息来确定目标是否已呈现在客户区,其中包括:

  • 可视区域相对于浏览器顶端位置;
  • 待加载资源相对于浏览器顶端位置。

在得到以上两点数据后,通过如下函数,便可得出某对象是否在浏览器可视区域了。
返回浏览器的可视区域位置

// 返回浏览器的可视区域位置 
function getClient(){ 
var l, t, w, h; 
l = document.documentElement.scrollLeft || document.body.scrollLeft; 
t = document.documentElement.scrollTop || document.body.scrollTop; 
w = document.documentElement.clientWidth; 
h = document.documentElement.clientHeight; 
return { left: l, top: t, width: w, height: h }; 
}

返回待加载资源位置
// 返回待加载资源位置 
function getSubClient(p){ 
var l = 0, t = 0, w, h; 
w = p.offsetWidth; 
h = p.offsetHeight; 
while(p.offsetParent){ 
l += p.offsetLeft; 
t += p.offsetTop; 
p = p.offsetParent; 
} 
return { left: l, top: t, width: w, height: h }; 
}

其中 函数getClient()返回浏览器客户区区域信息,getSubClient()返回目标模块区域信息。此时确定目标模块是否出现在客户区实际上是确定如上两个矩形是否相交。
// 判断两个矩形是否相交,返回一个布尔值 
function intens(rec1, rec2){ 
var lc1, lc2, tc1, tc2, w1, h1; 
lc1 = rec1.left + rec1.width / 2; 
lc2 = rec2.left + rec2.width / 2; 
tc1 = rec1.top + rec1.height / 2 ; 
tc2 = rec2.top + rec2.height / 2 ; 
w1 = (rec1.width + rec2.width) / 2 ; 
h1 = (rec1.height + rec2.height) / 2; 
return Math.abs(lc1 - lc2) < w1 && Math.abs(tc1 - tc2) < h1 ; 
}

现在基本上可以实现延时加载了,接下来,我们在window.onscroll事件中编写一些代码监控目标区域是否呈现在客户区。
<div style="width:100px; height:3000px"></div> 
<div id="div1" style="width:50px; height:50px; background:red; position:absolute; top:1000px"> 
</div>

var div1 = document.getElementById("div1"); 
window.onscroll = function(){ 
var prec1 = getClient(); 
var prec2 = getSubClient(div1); 
if (intens(prec1, prec2)) { 
alert("true"); 
} 
};

我们只需要在弹出窗口的地方加载我们需要的资源。
这里值得注意的是 : 目标对象呈现在客户区域时,会随着滚动而不断的弹出窗口。因此我们需要在弹出第一个窗口后取消对该区域的监测,这里用一个数组来收集需要监测的对象,同时将监测的逻辑抽出来。同时需要注意 onscroll事件和onresize事件都会改变游览器可视区域信息,因此在该类事件触发后需要重新计算,这里用autocheck()函数实现。
增加元素 :
<div id="div2" style="width:50px; height:50px; background:blue; position:absolute; top:2500px">

// 比较某个子区域是否呈现在浏览器区域 
function jiance(arr, prec1, callback){ 
var prec2; 
for (var i = arr.length - 1; i >= 0; i--) { 
if (arr[i]) { 
prec2 = getSubClient(arr[i]); 
if (intens(prec1, prec2)) { 
callback(arr[i]); 
// 加载资源后,删除监测 
delete arr[i]; 
} 
} 
} 
}

// 检测目标对象是否出现在客户区 
function autocheck(){ 
var prec1 = getClient(); 
jiance(arr, prec1, function(obj){ 
// 加载资源... 
alert(obj.innerHTML); 
}) 
} 
// 子区域一 
var d1 = document.getElementById("d1"); 
// 子区域二 
var d2 = document.getElementById("d2"); 
// 需要按需加载区域集合 
var arr = [d1, d2]; 
window.onscroll = function(){ 
// 重新计算 
autocheck(); 
} 
window.onresize = function(){ 
// 重新计算 
autocheck(); 
}
Javascript 相关文章推荐
js实现省市联动效果的简单实例
Feb 10 Javascript
再分享70+免费的jquery 图片滑块效果插件和教程
Dec 15 Javascript
实现无刷新联动例子汇总
May 20 Javascript
JS仿淘宝实现的简单滑动门效果代码
Oct 14 Javascript
基于BootStrap Metronic开发框架经验小结【二】列表分页处理和插件JSTree的使用
May 12 Javascript
JS作用域深度解析
Dec 29 Javascript
jQuery编写网页版2048小游戏
Jan 06 Javascript
jackson解析json字符串,首字母大写会自动转为小写的方法
Dec 22 Javascript
详解Vue之父子组件传值
Apr 01 Javascript
vxe-table vue table 表格组件功能
May 26 Javascript
js实现轮播图效果 z-index实现轮播图
Jan 17 Javascript
Element-ui树形控件el-tree自定义增删改和局部刷新及懒加载操作
Aug 31 Javascript
11款新鲜的jQuery插件[附所有demo下载]
Jan 24 #Javascript
基于jQuery的输入框无值自动显示指定数据的实现代码
Jan 24 #Javascript
精选的10款用于构建良好易用性网站的jQuery插件
Jan 23 #Javascript
返回对象在当前级别中是第几个元素的实现代码
Jan 20 #Javascript
有趣的JavaScript数组长度问题代码说明
Jan 20 #Javascript
无阻塞加载脚本分析[全]
Jan 20 #Javascript
善用事件代理,警惕闭包的性能陷阱。
Jan 20 #Javascript
You might like
PHP+Tidy-完美的XHTML纠错+过滤
2007/04/10 PHP
php面向对象全攻略 (四)构造方法与析构方法
2009/09/30 PHP
php cache类代码(php数据缓存类)
2010/04/15 PHP
ThinkPHP验证码使用简明教程
2014/03/05 PHP
PHP数字字符串左侧补0、字符串填充和自动补齐的几种方法
2014/05/10 PHP
php上传图片并压缩的实现方法
2015/12/22 PHP
YII2框架中使用yii.js实现的post请求
2017/04/09 PHP
Windows平台实现PHP连接SQL Server2008的方法
2017/07/26 PHP
PHP code 验证码生成类定义和简单使用示例
2020/05/27 PHP
javascript 简单抽屉效果的实现代码
2010/03/09 Javascript
js函数排序的实例代码
2013/07/01 Javascript
js Date概念详细介绍
2013/11/22 Javascript
解决json日期格式问题的3种方法
2014/02/02 Javascript
IE6-8中Date不支持toISOString的修复方法
2014/05/04 Javascript
indexOf 和 lastIndexOf 使用示例介绍
2014/09/02 Javascript
js判断数组key是否存在(不用循环)的简单实例
2016/08/03 Javascript
微信小程序 image组件binderror使用例子与js中的onerror区别
2017/02/15 Javascript
利用node.js如何搭建一个简易的即时响应服务器
2017/05/28 Javascript
使用live-server快速搭建本地服务器+自动刷新的方法
2018/03/09 Javascript
python实现求解列表中元素的排列和组合问题
2018/03/15 Python
Python实现的对本地host127.0.0.1主机进行扫描端口功能示例
2019/02/15 Python
python实现把两个二维array叠加成三维array示例
2019/11/29 Python
Python with标签使用方法解析
2020/01/17 Python
Python判断三段线能否构成三角形的代码
2020/04/12 Python
HTML5 Canvas锯齿图代码实例
2014/04/10 HTML / CSS
运动服饰每月订阅盒:Ellie
2018/04/29 全球购物
编码转换,怎样实现将GB2312编码的字符串转换为ISO-8859-1编码的字符串
2014/01/07 面试题
怎样声明接口
2014/09/19 面试题
营销总经理的岗位职责
2013/12/15 职场文书
考试退步检讨书
2014/01/15 职场文书
英语专业学生个人求职信
2014/01/28 职场文书
大一学生职业生涯规划
2014/03/11 职场文书
知识竞赛拉拉队口号
2014/06/16 职场文书
五好家庭事迹材料
2014/12/20 职场文书
《领导干部从政道德启示录》学习心得体会
2016/01/20 职场文书
vue+springboot实现登录验证码
2021/05/27 Vue.js