【原创】ImagesLazyLoad 图片延迟加载效果
之前在做一个图片浏览效果时,要看后面的小图必须等到前面的加载完,而且大图的位置是在大量的小图后面,导致大图要等到小图都加载完才能显示,为了解决这个问题,就想到了Lazyload效果。
现在很多网站都用了类似的效果,如淘宝、Bing等。
这个图片延迟加载效果是在Lazyload的基础上扩展的,主要扩展了获取img元素,获取src和图片加载的部分。
兼容:ie6/7/8, firefox 3.5.5, opera 10.10, safari 4.0.4, chrome 3.0
其中safari和chrome部分功能不支持。

程序说明
【获取图片】
先定义filter函数作为筛选程序,
- JScript code
-
var getSrc = opt.getSrc, filter = $$F.bind( this._filter, this, opt["class"], getSrc ? function(img){ return getSrc(img); } : function(img){ return img.getAttribute( attribute ) || img.src; }, opt.holder );
然后用这个filter函数筛选出需要的图片集合:
- JScript code
-
this._elems = $$A.filter( opt.images || container.getElementsByTagName("img"), filter );
如果要自定义图片集合可以在程序可选参数的images属性来设置,否则自动从容器获取img元素作为图片集合。
这里的filter其实是包装了筛选样式cls、获取src的方法getSrc和占位图holder三个参数的_filter筛选程序。
在_filter程序中,会对图片集合进行筛选和整理。
如果自定义了"class"筛选样式,会自动排除样式不对应的图片:
- JScript code
-
if ( cls && img.className !== cls ) return false;
再用getSrc获取原图地址,即实际要显示的图片地址。
如果有自定义getSrc会优先使用。
没有的话,再通过保存原图地址的_attribute自定义属性从元素获取。
最后才直接从元素的src属性获取。
接着排除src不存在的:
if ( !src ) return false;
要注意处理原图地址就是元素当前src的情况:
- JScript code
-
if ( src == img.src ) { if ( img.complete || $$B.chrome || $$B.safari ) return false; img.removeAttribute("src"); }
如果complete为true,说明图片已经载入完成了,可以排除;
如果是chrome或safari,不能取消当前加载,所以也排除掉(具体看图片的HTTP请求部分)。
否则,用removeAttribute移除src属性来取消图片当前的加载。
如果设置了holder占位图,就重新设置图片src:
if ( holder ) { img.src = holder; }
最后把原图地址记录到元素的_attribute自定义属性中:
img.setAttribute( this._attribute, src );
逐个图片元素筛选整理后,就得到要加载的图片集合了。
【图片加载】
ImagesLazyLoad相比LazyLoad,已经实现了_onLoadData加载程序,不需要再自己定义加载。
在_onLoadData程序中,主要是用来显示图片。
先用判断是否有_attribute自定义属性:
- JScript code
-
if ( this._hasAttribute( img ) ) { ... }
在_hasAttribute方法中是这样判断的:
- JScript code
-
this._hasAttribute = $$B.ie6 || $$B.ie7 ? function(img){ return attribute in img; } : function(img){ return img.hasAttribute( attribute ); };
由于ie6/7跟其他浏览器对attribute和property的理解不同,所以要分开处理,详细参考这里的attribute/property。
为了保证兼容性,程序会优先使用attribute的方式来操作自定义属性。
当img有_attribute自定义属性时,就用getAttribute来获取原图地址,并设置img的src,在用removeAttribute来移除自定义属性。
移除的意义在于,当有多个实例使用同一个元素时,能保证图片加载一次后就不会重复加载,即防止实例间的冲突。
【图片的HTTP请求】
这里说说开发过程中发现的一些关于图片加载的问题。
首先是加载空字符串的问题,如果给img的src设为空字符串的话,可能会得到意料之外的结果。
例如在 http://xxx/test.htm 里面的 <img src=""> 会发生以下情况:
ie 会产生相对地址的请求,即:http://xxx/
Safari/Chrome 会产生当前页面地址的请求,即:http://xxx/test.htm
Opera/Firefox 不会产生请求
详细参考Nicholas C. Zakas的“Empty image src can destroy your site”。
如果不想加载图片,不应该把src设为空值,因为还可能会发出请求,浪费资源。
可以像程序那样,通过removeAttribute来移除就行了。
还有一个问题是在Safari和Chrome,由于webkit内核的bug,正在加载的图片并不能取消加载。
所以程序在取消图片加载的部分,如果是Safari或Chrome会继续加载,不进行延迟。
这个问题最初从lifesinger的datalazyload的说明部分看到的,具体可以自己用Fiddler来测试。
更多相关资料可以参考lifesinger的“图片的HTTP请求”。
【继承结构】
在发布的程序中,这是第一个用了继承的,本人平时也没怎么用到,所以还不成熟,算是试试水吧。
程序用wrapper来做继承,详细参考工具库的说明。
先用wrapper给ImagesLazyLoad包装(继承)LazyLoad:
- JScript code
-
var ImagesLazyLoad = $$.wrapper(function(options) { ... }, LazyLoad);
再用extend扩展prototype,添加子类的方法函数:
- JScript code
-
$$.extend( ImagesLazyLoad.prototype, { ... });
其中_initialize方法用来设置子类属性,由于覆盖了父类的同名方法,所以要通过LazyLoad.prototype._initialize来调用,还要注意用call来修正this。
还有_setOptions方法用来设置子类的可选属性:
- JScript code
-
return LazyLoad.prototype._setOptions.call(this, $$.extend({ ... }, $$.extend( options, { onLoadData: this._onLoadData })));
子类的_setOptions方法也覆盖了父类的方法,解决方法同_initialize。
其中第一个参数是子类的可选属性,第二个参数是子类定义的属性,即不再是可选而是由程序来定义的属性。
总体来说,这是个简陋的继承,等以后积累了一定经验再来扩展吧。
使用技巧【设置src】
有几个方法可以设置原图地址:
1,正常设置src:渐进增强,不支持js时也能显示,但chrome和safari有bug,不支持这种方式;
2,把原图地址设置到自定义属性中:所有浏览器都兼容,但在不支持js时图片不能显示;
3,用自定义函数获取:使用在比较复杂的情况,需要手动设置。
具体还是要根据实际情况来选择。
【设置holder】
如果使用了holder占位图,程序会自动设置图片元素显示占位图。
推荐使用loading图片来设置,但loading图往往跟原图的尺寸是不同的。
如果img设置了原图宽高,又想保持loading图的尺寸,把它设为背景就可以了。
但这样在ie下,默认会有一个小图标(不设置src)。
要去掉这个小图标可以设置holder为一个透明图片的链接,或者参考这里的TRANSPARENT“做”一个透明图片。
实例中也是这样设置的,可以参考一下。
【执行程序】
千万不能在window.onload中执行,因为那时图片都已经加载完了。
而应该在容器后面(window的话是文档结尾)或DOMContentLoaded中执行。
程序源码
- JScript code
-
var ImagesLazyLoad = $$.wrapper(function(options) { this._initialize( options ); //如果没有元素就退出 if ( this.isFinish() ) return; //初始化模式设置 this._initMode(); //进行第一次触发 this.resize(true); }, LazyLoad); $$.extend( ImagesLazyLoad.prototype, { //初始化程序 _initialize: function(options) { LazyLoad.prototype._initialize.call(this, [], options); //设置子类属性 var opt = this.options; this.onLoad = opt.onLoad; var attribute = this._attribute = opt.attribute; //设置加载图片集合 var getSrc = opt.getSrc, filter = $$F.bind( this._filter, this, opt["class"], getSrc ? function(img){ return getSrc(img); } : function(img){ return img.getAttribute( attribute ) || img.src; }, opt.holder ); this._elems = $$A.filter( opt.images || this._container.getElementsByTagName("img"), filter ); //判断属性是否已经加载的方法 this._hasAttribute = $$B.ie6 || $$B.ie7 ? function(img){ return attribute in img; } : function(img){ return img.hasAttribute( attribute ); }; }, //设置默认属性 _setOptions: function(options) { return LazyLoad.prototype._setOptions.call(this, $$.extend({//默认值 images: undefined,//图片集合 attribute: "_lazysrc",//保存原图地址的自定义属性 holder: "",//占位图 "class": "",//筛选样式 getSrc: undefined,//获取原图地址程序 onLoad: function(){}//加载时执行 }, $$.extend( options, { onLoadData: this._onLoadData }))); }, //筛选整理图片对象 _filter: function(cls, getSrc, holder, img) { if ( cls && img.className !== cls ) return false;//排除样式不对应的 //获取原图地址 var src = getSrc(img); if ( !src ) return false;//排除src不存在的 if ( src == img.src ) { //排除已经加载或不能停止加载的 if ( img.complete || $$B.chrome || $$B.safari ) return false; img.removeAttribute("src");//移除src } if ( holder ) { img.src = holder; } //用自定义属性记录原图地址 img.setAttribute( this._attribute, src ); return true; }, //显示图片 _onLoadData: function(img) { var attribute = this._attribute; if ( this._hasAttribute( img ) ) { img.src = img.getAttribute( attribute ); img.removeAttribute( attribute ); this.onLoad( img ); } } });
sf
一早,来了…
赶上了,先占座
飘过,占个位~~~~
好 顶
我发了封邮件给你 你快点看一下…………………..
楼主总是给人带来惊喜…
赞“`

~~~~~~~~jF
原来是你啊
谢谢支持
顶
好东东啊
顶一下
强烈支持……………
很帅, 很酷,很拽。
我刚才看了下
速度好快啊
谢谢支持
顶一下
再顶一下吧
好,再顶一下
…………………..
#4楼 得分:0回复于:2010-03-08 09:41:23一早,来了…
顶一下下
xiexielouzhufenxiang
接分,楼主很厉害
看来我是错过了哈
您又有成果了哈
学习了,哈哈
学习了,还是比较难,谢谢分享!
学习了,哈哈
Nice! Very Good!
飘过,占个位~~~~
看看啊
多谢多谢。。。。
照片裡的美女是誰啊?
照片裡的美女是誰啊?
jf……………………………….
你这个好麻烦啊……我也写了一个欢迎评论!!!!!!http://www.cnblogs.com/jacd/archive/2010/03/25/1696085.html
好贴 顶一下。。。。
mark
nb[b][/b]
哈,不好意意思,我是来看图片的。
顶一下
下来看看
有没电子单片机的高手啊。。。。。。。
对于牛逼的东西,我总是要做个记号
强力顶起.
坚持每天回帖子
喂喂喂
不错阿…谢谢了
好东东,收藏之。。。
学习学习!
不错!!很好啊!学习学习~~~~
路过,看不懂
好定西。收藏
哇! 楼主你太有才了
谢谢楼主,
收藏一下,呵呵,,,
看看先~~~~~~..
恩,知道了
好东西啊
一定要顶的………………….
好东西啊,顶。
谢谢分享。
jf~~~~~~~~
不错~
顶起了!收下了
太深奥了,愣是没搞懂
你杂就这么厉害呢
传说中的AV WEB?
学习了,赞一个
不错,有学习才进步
看看。。。。。。。
好也啊。。。。。。。。。。。。。。。。
这么好的贴子没看到
阿弥陀佛,
学习学习
断恶修善,灾消福来.
人心善风调雨顺
阿弥陀佛
老实说我不喜欢JScript还用纯正的JS会比较好。
我感觉他和JQUERY差不多。
收藏着,等着用……
学习,收藏了,
接分,飘过~~~~~
强烈支持!!!!!!!!!!!
原来是这样实现的啊,赞一个!~~~~~
var ImagesLazyLoad = $$.wrapper(function(options) {
this._initialize( options );
//如果没有元素就退出
if ( this.isFinish() ) return;
//初始化模式设置
this._initMode();
//进行第一次触发
this.resize(true);
}, LazyLoad);
$$.extend( ImagesLazyLoad.prototype, {
//初始化程序
_initialize: function(options) {
LazyLoad.prototype._initialize.call(this, [], options);
//设置子类属性
var opt = this.options;
this.onLoad = opt.onLoad;
var attribute = this._attribute = opt.attribute;
//设置加载图片集合
var getSrc = opt.getSrc,
filter = $$F.bind( this._filter, this,
opt["class"],
getSrc ? function(img){ return getSrc(img); }
: function(img){ return img.getAttribute( attribute ) || img.src; },
opt.holder
);
this._elems = $$A.filter(
opt.images || this._container.getElementsByTagName("img"), filter
);
//判断属性是否已经加载的方法
this._hasAttribute = $$B.ie6 || $$B.ie7
? function(img){ return attribute in img; }
: function(img){ return img.hasAttribute( attribute ); };
},
//设置默认属性
_setOptions: function(options) {
return LazyLoad.prototype._setOptions.call(this, $$.extend({//默认值
images: undefined,//图片集合
attribute: "_lazysrc",//保存原图地址的自定义属性
holder: "",//占位图
"class": "",//筛选样式
getSrc: undefined,//获取原图地址程序
onLoad: function(){}//加载时执行
}, $$.extend( options, {
onLoadData: this._onLoadData
})));
},
//筛选整理图片对象
_filter: function(cls, getSrc, holder, img) {
if ( cls && img.className !== cls ) return false;//排除样式不对应的
//获取原图地址
var src = getSrc(img);
if ( !src ) return false;//排除src不存在的
if ( src == img.src ) {
//排除已经加载或不能停止加载的
if ( img.complete || $$B.chrome || $$B.safari ) return false;
img.removeAttribute("src");//移除src
}
if ( holder ) { img.src = holder; }
//用自定义属性记录原图地址
img.setAttribute( this._attribute, src );
return true;
},
//显示图片
_onLoadData: function(img) {
var attribute = this._attribute;
if ( this._hasAttribute( img ) ) {
img.src = img.getAttribute( attribute );
img.removeAttribute( attribute );
this.onLoad( img );
}
}
});
学习,受教了!
学习一下
不错 顶一个
强。。。。。
很不错,收藏了。
学习了
谢谢支持
牛人,学习啊
顶一下
收藏!
支持一个,这个不错
占个位置,学习学习!!顶
谢谢支持
受教了,支持
顶一下
fffffffffffffff
jf!!!!!!!!
谢谢支持
顶一下