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 相关文章推荐
jquery 最简单易用的表单验证插件
Feb 27 Javascript
jquery中ajax学习笔记一
Oct 16 Javascript
js移除事件 js绑定事件实例应用
Nov 28 Javascript
解决Jquery load()加载GB2312页面时出现乱码的两种方案
Sep 10 Javascript
图解Sublime Text3使用技巧
Dec 21 Javascript
AngularJS 异步解决实现方法
Jun 12 Javascript
JavaScript屏蔽Backspace键的实现代码
Nov 02 Javascript
node.js博客项目开发手记
Mar 16 Javascript
vue移动端城市三级联动组件使用详解
Jul 26 Javascript
基于Express框架使用POST传递Form数据
Aug 10 Javascript
浅谈Vue3.0新版API之composition-api入坑指南
Apr 30 Javascript
微信小程序实现自定义底部导航
Nov 18 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
人大复印资料处理程序_补充篇
2006/10/09 PHP
处理php自动反斜杠的函数代码
2010/01/05 PHP
批量获取memcache值并按key的顺序返回的实现代码
2011/06/14 PHP
PHP If Else(elsefi) 语句
2013/04/07 PHP
php遍历、读取文件夹中图片并分页显示图片的方法
2016/11/15 PHP
php观察者模式应用场景实例详解
2017/02/03 PHP
使用dynatrace-ajax跟踪JavaScript的性能
2010/04/12 Javascript
使用upstart把nodejs应用封装为系统服务实例
2014/06/01 NodeJs
分享9点个人认为比较重要的javascript 编程技巧
2015/04/27 Javascript
Es6 Generator函数详细解析
2018/02/24 Javascript
解决cordova+vue 项目打包成APK应用遇到的问题
2019/05/10 Javascript
解决layer图标icon不加载的问题
2019/09/04 Javascript
微信域名检测接口调用演示步骤(含PHP、Python)
2019/12/08 Javascript
Python语言的12个基础知识点小结
2014/07/10 Python
利用Python实现微信找房机器人实例教程
2019/03/10 Python
Python 学习教程之networkx
2019/04/15 Python
python各类经纬度转换的实例代码
2019/08/08 Python
Python利用Scrapy框架爬取豆瓣电影示例
2020/01/17 Python
利用python实现逐步回归
2020/02/24 Python
Python如何通过百度翻译API实现翻译功能
2020/04/02 Python
python 生成正态分布数据,并绘图和解析
2020/12/21 Python
用纯css3实现的图片放大镜特效效果非常不错
2014/09/02 HTML / CSS
html5文字阴影效果text-shadow使用示例
2013/07/25 HTML / CSS
美国转售二手商品的电子商务平台:BLINQ
2018/12/13 全球购物
Ibatis的核心配置文件都有什么
2014/09/08 面试题
团队经理竞聘书
2014/03/31 职场文书
中班上学期幼儿评语
2014/04/30 职场文书
保研推荐信
2014/05/09 职场文书
中专生自荐信
2014/06/25 职场文书
电话客服专员岗位职责
2014/06/28 职场文书
简单租房协议书(范本)
2014/10/13 职场文书
婚礼领导致辞大全
2015/07/28 职场文书
浅谈redis五大数据结构和使用场景
2021/04/12 Redis
python-for x in range的用法(注意要点、细节)
2021/05/10 Python
详解Python中__new__方法的作用
2022/03/31 Python
Golang map映射的用法
2022/04/22 Golang