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编程小常识很有用
Nov 26 Javascript
JavaScript之IE的fireEvent方法详细解析
Nov 20 Javascript
JS小功能(列表页面隔行变色)简单实现
Nov 28 Javascript
刷新页面的几种方法小结(JS,ASP.NET)
Jan 07 Javascript
Angularjs实现mvvm式的选项卡示例代码
Sep 08 Javascript
详解如何使用webpack打包Vue工程
May 27 Javascript
js禁止浏览器页面后退功能的实例(推荐)
Sep 01 Javascript
node 利用进程通信实现Cluster共享内存
Oct 27 Javascript
微信小程序 Storage更新详解
Jul 16 Javascript
解决layui-table单元格设置为百分比在ie8下不能自适应的问题
Sep 28 Javascript
解决vue项目F5刷新mounted里的函数不执行问题
Nov 05 Javascript
手把手带你搭建一个node cli的方法示例
Aug 07 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比较多维数组中值的大小排序实现代码
2012/09/08 PHP
php 模拟post_验证页面的返回状态(实例讲解)
2013/10/28 PHP
PHP 实现浏览记录并按日期分组
2017/05/11 PHP
jquery中load方法的用法及注意事项说明
2014/02/22 Javascript
jQery使网页在显示器上居中显示适用于任何分辨率
2014/06/09 Javascript
深入分析下javascript中的[]()+!
2015/07/07 Javascript
Nodejs中session的简单使用及通过session实现身份验证的方法
2016/02/04 NodeJs
jQuery实现图片局部放大镜效果
2016/03/17 Javascript
jQuery删除节点用法示例(remove方法)
2016/09/08 Javascript
jQuery.datatables.js插件用法及api实例详解
2016/10/28 Javascript
JS中parseInt()和map()用法分析
2016/12/16 Javascript
微信小程序 缓存(本地缓存、异步缓存、同步缓存)详解
2017/01/17 Javascript
详解微信小程序开发之——wx.showToast(OBJECT)的使用
2017/01/18 Javascript
js实现类bootstrap模态框动画
2017/02/07 Javascript
详解Vuejs2.0 如何利用proxyTable实现跨域请求
2017/08/03 Javascript
vue自定义全局共用函数详解
2018/09/18 Javascript
微信小程序实现的自定义分享功能示例
2019/02/12 Javascript
jquery.pager.js实现分页效果
2019/07/29 jQuery
Python中bisect的用法
2014/09/23 Python
Python中利用sorted()函数排序的简单教程
2015/04/27 Python
详解Python3中字符串中的数字提取方法
2017/01/14 Python
Python+PIL实现支付宝AR红包
2018/02/09 Python
使用pandas对矢量化数据进行替换处理的方法
2018/04/11 Python
Python lambda表达式用法实例分析
2018/12/25 Python
Python requests模块cookie实例解析
2020/04/14 Python
Django如何使用redis作为缓存
2020/05/21 Python
Python在字符串中处理html和xml的方法
2020/07/31 Python
CSS3实现可关闭的下拉手风琴菜单效果
2015/08/31 HTML / CSS
GoDaddy英国:全球排名第一的域名注册商
2018/06/08 全球购物
为什么group by 和order by会使查询变慢
2014/05/16 面试题
奥巴马连任演讲稿
2014/05/15 职场文书
2014公司年终工作总结
2014/12/19 职场文书
2015年医德考评自我评价
2015/03/03 职场文书
解决Python中的modf()函数取小数部分不准确问题
2021/05/28 Python
Redis命令处理过程源码解析
2022/02/12 Redis
「玫瑰之王的葬礼」舞台剧主视觉图公开
2022/03/21 日漫