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 相关文章推荐
为Yahoo! UI Extensions Grid增加内置的可编辑器
Mar 10 Javascript
javascript 一些用法小结
Sep 11 Javascript
safari,opera嵌入iframe页面cookie读取问题解决方法
Jun 23 Javascript
jquery easyui combobox模糊过滤(示例代码)
Nov 30 Javascript
javascript面向对象特性代码实例
Jun 12 Javascript
JavaScript检测弹出窗口是否已经关闭的方法
Mar 24 Javascript
JS事件添加和移出的兼容写法示例
Jun 20 Javascript
利用Vue.js实现checkbox的全选反选效果
Jan 18 Javascript
vue.js组件之间传递数据的方法
Jul 10 Javascript
JS HTML图片显示Canvas 压缩功能
Jul 21 Javascript
CKEditor4配置与开发详细中文说明文档
Oct 08 Javascript
vue在App.vue文件中监听路由变化刷新页面操作
Aug 14 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
虹吸壶是谁发明的?煮出来的咖啡好喝吗
2021/03/04 冲泡冲煮
eAccelerator的安装与使用详解
2013/06/13 PHP
解析PHP中一些可能会被忽略的问题
2013/06/21 PHP
浅析ThinkPHP中的pathinfo模式和URL重写
2014/01/06 PHP
Symfony2学习笔记之系统路由详解
2016/03/17 PHP
laravel学习教程之关联模型
2016/07/30 PHP
php实现文章置顶功能的方法
2016/10/20 PHP
PHP 实现从数据库导出到.csv文件方法
2017/07/06 PHP
PHP实现的redis主从数据库状态检测功能示例
2017/07/20 PHP
PHP实现合并两个排序链表的方法
2018/01/19 PHP
yii2实现Ueditor百度编辑器的示例代码
2018/11/02 PHP
Laravel Validator自定义错误返回提示消息并在前端展示
2019/05/09 PHP
IE8 兼容性问题(属性名区分大小写)
2009/06/04 Javascript
Javascript实现CheckBox的全选与取消全选的代码
2010/07/20 Javascript
jquery教程限制文本框只能输入数字和小数点示例分享
2014/01/13 Javascript
jquery中checkbox全选失效的解决方法
2014/12/26 Javascript
深入理解JavaScript系列(19):求值策略(Evaluation strategy)详解
2015/03/05 Javascript
JavaScript事件学习小结(五)js中事件类型之鼠标事件
2016/06/09 Javascript
微信、QQ、微博、Safari中使用js唤起App
2018/01/24 Javascript
Angular 向组件传递模板的两种方法
2018/02/23 Javascript
vue中锚点的三种方法
2018/07/06 Javascript
vue-quill-editor 自定义工具栏和自定义图片上传路径操作
2020/08/03 Javascript
vant-ui组件调用Dialog弹窗异步关闭操作
2020/11/04 Javascript
[04:03]2014DOTA2西雅图国际邀请赛 LGD战队巡礼
2014/07/07 DOTA
pygame学习笔记(5):游戏精灵
2015/04/15 Python
儿童python练习实例
2018/05/27 Python
selenium python 实现基本自动化测试的示例代码
2019/02/25 Python
python隐藏终端执行cmd命令的方法
2019/06/24 Python
浅谈python opencv对图像颜色通道进行加减操作溢出
2020/06/03 Python
使用HTML5和CSS3表单验证功能
2017/05/05 HTML / CSS
三星印度官网:Samsung印度
2019/08/03 全球购物
CAD制图设计师自荐信
2014/01/29 职场文书
贸易经济专业自荐书
2014/06/29 职场文书
学习教师法的心得体会
2014/09/03 职场文书
为什么MySQL 删除表数据 磁盘空间还一直被占用
2021/10/16 MySQL
python的列表生成式,生成器和generator对象你了解吗
2022/03/16 Python