前言
图片延迟加载技术其实应该被用得很多了,令人汗颜的是我居然之前一直没有用过,今天还是一个后端的大哥给提出来的,于是我便趁着中午休息的时间做了一下研究,这里提出来和大家讨论一下。
PS:小生初学,各位有问题可以提出来讨论
延迟加载原理
延迟加载有多种实现,我选择了其中一种:
为img标签src设置统一的图片链接,而将真实链接地址装在自定义属性中。
所以开始时候图片是不会加载的,我们将满足条件的图片的src重置为自定义属性便可实现延迟加载功能
当然还有其它的方案,里面我还比较青睐的就是将dom结构装入textare,满足条件时候将之载入,这里我便不讨论了。
来看看我们用到的共用图片:
问题
其实这种方案不能说没有问题,因为我会遍历所有的img标签,相当于把整个页面走了一次,万一我有1000张图片,我想效率会是很大的问题!
PS:页面上出现1000张图片这种事情我是不会让其发生的,就算真的出现,也会有对应的解决之法,这里不扯远了,于是我们开始今天的准备工作。
给我100张图片
既然要做延迟加载,当然需要图片了,所以给我100张图片吧!!!
咳咳,其实我是一个程序员,所以我不会一张一张的搞的,下面是我的处理步骤:
① 在google图片里面搜索图片
② 将主要节点给拷贝出来
③ 在后面改写代码,将所有的img搞出来并装入我们的节点
④ 批量操作节点
反正最后就成了这个样子啦:
我们轻松加愉快的获得了100张图片(具体有没有100张我没有数。。。)
功能实现
代码很简单,我这里就直接给贴出来了,我们一起来看看吧:
复制代码
function imgLazyLoad(container) {
container = container || $(window); //需要时jquery对象
var imgArr = {};
initImg();
lazyLoad();
container.scroll(function () {
lazyLoad();
});
$(window).resize(function () {
initImg();
});
function initImg() {
$('img').each(function () {
var el = $(this);
if (el.attr('lazy-src') && el.attr('lazy-src') != '') {
var offset = el.offset();
if (!imgArr[offset.top]) {
imgArr[offset.top] = [];
}
imgArr[offset.top].push(el);
}
});
}
function lazyLoad() {
var height = container.height();
var srollHeight = container.scrollTop();
for (var k in imgArr) {
if (parseInt(k) < srollHeight + height) {
var _imgs = imgArr[k];
for (var i = 0, len = _imgs.length; i < len; i++) {
var tmpImg = _imgs[i];
if (tmpImg.attr('lazy-src') && tmpImg.attr('lazy-src') != '') {
tmpImg.attr('src', tmpImg.attr('lazy-src'));
tmpImg.removeAttr('lazy-src');
}
}
delete imgArr[k];
}
}
} //lazyLoad
}
imgLazyLoad($('#con'));
复制代码
① 我们首先会给函数传入一个容器,不传的话默认就是window
② 然后我这里会初始化整个img,事实上就是遍历了,我会把同时处于某一个的高度的图片给他搞出来放到一起:
③ 当我们初始化结束后,我这里便定义了一个延迟加载的函数,他会取得当前的视图高度与滚动条高度,然后遍历我们的对象,将高度在他之上的图片给显示出来(这一步很关键哦)
当元素图片一旦加载的话便移除对象并且移除元素的lazy-src属性,因为当我们窗口大小发生变化后,我们会重新计算图片位置,计算中加载的元素不具备lazy-src属性便忽略了。
以上我们的功能便结束了,我以为好像就这样结束了,于是就结束了。。。。。。真的结束了吗?
狗屁延迟加载
请思考以下场景,叶小钗现在正在看苍老师的漫画呢,叶小钗有好几期没看了呢,于是叶小钗猥琐的打开了多个窗口慢慢等待图片加载!自己就高高兴兴玩起游戏来。
半个小时后,叶小钗打开网页一看,恩不错所有网页图片都加载出来了呢!!
但是往下一番,尼玛怎么下面的图片没有出来!!!我的苍老师呢?换了几个网页都是这样,所以叶小钗是否憎恨延迟加载!!!!
PS:以上场景只是笑话,不可能发生的,但是却是我们需要考虑到的问题。
当页面比较空闲的情况下,我们为什么要延迟加载呢?所以我们需要将以上代码做一点改变,我是这样想的:
若是页面长时间没有鼠标移动的话,我这里就继续加载剩下图片了,一旦鼠标运动,我这里就暂停一下
直接上代码吧:
复制代码
1 function imgLazyLoad(container) {
2
3 var imgLazyLoadTimer = null;
4 var resetImglazy = null;
5
6 container = container || $(window); //需要时jquery对象
7 var imgArr = {};
8 initImg();
9 lazyLoad();
10 autoLoad();
11 container.scroll(function () {
12 lazyLoad();
13 });
14 $(window).resize(function () {
15 initImg();
16 });
17 $(document).mousemove(function () {
18 clearTimeout(imgLazyLoadTimer);
19 if (resetImglazy) clearTimeout(resetImglazy);
20 resetImglazy = setTimeout(function () {
21 autoLoad();
22 }, 5000);
23 });
24 function initImg() {
25 $('img').each(function () {
26 var el = $(this);
27 if (el.attr('lazy-src') && el.attr('lazy-src') != '') {
28 var offset = el.offset();
29 if (!imgArr[offset.top]) {
30 imgArr[offset.top] = [];
31 }
32 imgArr[offset.top].push(el);
33 }
34 });
35 }
36
37 function lazyLoad() {
38 var height = container.height();
39 var srollHeight = container.scrollTop();
40 for (var k in imgArr) {
41 if (parseInt(k) < srollHeight + height) {
42 var _imgs = imgArr[k];
43 for (var i = 0, len = _imgs.length; i < len; i++) {
44 var tmpImg = _imgs[i];
45 if (tmpImg.attr('lazy-src') && tmpImg.attr('lazy-src') != '') {
46 tmpImg.attr('src', tmpImg.attr('lazy-src'));
47 tmpImg.removeAttr('lazy-src');
48 }
49 }
50 delete imgArr[k];
51 }
52 }
53 } //lazyLoad
54
55 function autoLoad() {
56 var _key = null;
57 for (var k in imgArr) {
58 if (!_key) {
59 _key = k;
60 break;
61 }
62 }
if(!_key) return false;
63 var _imgs = imgArr[_key];
64 for (var i = 0, len = _imgs.length; i < len; i++) {
65 var tmpImg = _imgs[i];
66 if (tmpImg.attr('lazy-src') && tmpImg.attr('lazy-src') != '') {
67 tmpImg.attr('src', tmpImg.attr('lazy-src'));
68 tmpImg.removeAttr('lazy-src');
69 }
70 }
71 delete imgArr[_key];
72 if (imgLazyLoadTimer) {
73 clearTimeout(imgLazyLoadTimer);
74 }
75 imgLazyLoadTimer = setTimeout(autoLoad, 1000);
76 }
77 } //imgLazyLoad
78 imgLazyLoad($('#con'));
复制代码
具体我还没怎么测试呢,各位看看吧,有问题请提出来哦
昨天有朋友提出有问题,我解决了下下面上新代码:
View Code
演示地址
http://sandbox.runjs.cn/show/7vpjps1r
结语
中午不睡下午崩溃,我这里感觉去睡一会,若是您觉得这篇文章不错请点一下推荐,若是您发现有何问题请一定提出来!
哎,没有功劳也有苦劳,没有苦劳我有疲劳哦,各位看在中午没睡的情况下,顶下吧。。。。:)
不足与交流
呵呵,根据这个功能居然会有朋友关注,并提出了宝贵的意见,真的十分感谢,以下是朋友的见解:
通过阅读原作中的代码,可以看到,在上述几个步骤中存在如下几个问题:
用户指定的图片容器其实没有用;
自动扫描全部被延迟加载的图片信息(按照作者的意图其实应该是仅扫描指定容器内的图片),另外,图片扫描的代码可以写的更简练;
加载当前屏幕图片时,计算某图片是否在当前窗口的算法不够严谨,仅当容器的高度小于当前浏览器窗口高度时算法有效,其他情况下均无效;
另外,我认为这里判断lazy-src是否为空几乎没有必要,因为实际应用中几乎不可能出现,更可能出现的是地址错误,但是这种错误根本没法去检测出现;
针对上述四点问题,我只重点说一下第三点。
我们不妨做一个假设,假设所有的图片不是在做着假设的id为con的div中,而是直接在body中,那么根据原来的算法,在计算某图片是否属于当前屏幕时,结果总是为true,此时延迟加载算法几乎完全失效了!
为什么呢?看看原作的代码,如果图片的容器是body,即整个document,那么代码var height = container.height();得到的高度值就是整个页面的高度,这个高度超过所有图片的offset().top的高度,因此导致的结果就是,所有的图片都被认为是在当前屏幕而被一次性加载,这跟不使用延迟加载有什么不同呢?
修改后的代码:
//延迟加载图片
var imageloadCurrentWindower =function(container){
//在空闲时循环加载剩余图片工作的定时器
var autoLoaderTimer =null;
//在空闲时启动加载剩余图片工作的定时器
var restartAutoLoaderTimer =null;
//图片容器
this.container = container || $(document);//容器默认为整个文档
//所有图片
this.allImages;
//初始化延迟加载的图片的信息
this.scanLazyImageInfo =function(){
allImages ={};
this.container.find('img[lazy-src]').each(function(){
var el = $(this);
var offset = el.offset();
if(!allImages[offset.top]){
allImages[offset.top]=[];
}
allImages[offset.top].push(el);
});
}
//加载当前屏幕中被延迟加载的图片
this.loadCurrentWindow =function(){
var h1,h2;
h1 =this.container.height();
h2 = $(window).height();
var height =this.container.scrollTop()+(h1 > h2 ? h2 : h1);
for(var k in allImages){
if(parseInt(k)< height){
loadImages(allImages, k);
continue;
}
break;
}
}
//页面空闲时自动加载未加载的图片
this.autoLoad =function(){
// 取一行图片加载
for(var k in allImages){
loadImages(allImages, k);
break;
}
//取消上一个定时器
if(autoLoaderTimer){
clearTimeout(autoLoaderTimer);
}
//重新生成定时器,1秒后如果页面仍然空闲则加载下一行图片
autoLoaderTimer = setTimeout(autoLoad,1000);
}
//加载图片
loadImages =function(allImages, _key){
var _imgs = allImages[_key];
for(var i =0, len = _imgs.length; i < len; i++){
var tmpImg = _imgs[i];
tmpImg.attr('src', tmpImg.attr('lazy-src'));
tmpImg.removeAttr('lazy-src');
}
delete allImages[_key];
}
//扫描所有被延迟加载的图片信息
this.scanLazyImageInfo();
//加载当前窗口中的图片
this.loadCurrentWindow();
//监视当前容器的滚动条滚动事件
this.container.scroll(function(){
loadCurrentWindow();
});
//监视窗口的尺寸改变事件
$(window).resize(function(){
scanLazyImageInfo();
loadCurrentWindow();
});
//监视页面是否空闲,以鼠标是否移动为标志
$(document).mousemove(function(){
//清除空闲时自动加载图片的定时器
clearTimeout(autoLoaderTimer);
//如果存在清除重启空闲时自动加载图片的定时器
if(restartAutoLoaderTimer)
clearTimeout(restartAutoLoaderTimer);
//重新生成重启空闲时自动加载图片的定时器
restartAutoLoaderTimer = setTimeout(function(){
autoLoad();
},5000);
});
//启动自动加载当前屏幕外图片
this.autoLoad();
}
//页面下载完成后即刻开始延迟加载图片工作
$(document).ready(function(){
//启动延迟加载,支持$(document)
imageloadCurrentWindower($("#con"));
});
您可以考虑给小钗发个小额微信红包以资鼓励
本文转自叶小钗博客园博客,原文链接:http://www.cnblogs.com/yexiaochai/archive/2013/06/06/3120987.html,如需转载请自行联系原作者