今天在做页面的时候需要实现图片预加载的功能,保证迅速正常的显示。
解决方式:
用css
方式,将图片作为背景图片加载
.pic{background-image: url(image/demo.png) no-repeat -9999px -9999px;}
这种方式的前提是,进入页面后的图片不会立即用到。如果一打开页面就需要看到完整图片,这种方式也还是挺耗时间的。
通过javascript
加载图片:
首先创建一个Image对象,实现图片的预加载;然后检测图片是否存在缓存中如果存在就直接调用回调函数,若不在执行 onload()
方法。
function preLoadImages(url,callback){
var img = new Image();
img.src = url;
if(img.complate){ //判断图片是否在缓存中
callback(img);
return;
}
img.onload = function(){ //下载图片异步调用callback函数
callback(img);
}
}
分析:这个方式还是有一些问题
1.创建了一个临时的匿名函数来作为图片的onload
事件处理函数,形成了闭包。闭包有保存外部运行环境的能力(依赖于作用域链的实现),所以imag.onload
这个函数内部有保存了对img
的引用,这样就形成了循环作用,导致内存泄露。(这种方式只存在于与ie6,高版本的浏览器一般都不会出现内存泄露)。
2.只考虑了静态图片的加载,忽略了gif等动态图片,这些动态图片可能多次触发onload
事件。
解决方式:
img.onload = function(){
img.onload = null;
callback(img);
}
关于这段代码,看相关博文里的叙述,原因如下:
经过对多个浏览器版本的测试,发现ie、opera下,当图片加载过一次以后,如果再有对该图片的请求时,由于浏览器已经缓存住这张图片了,不会再发起一次新的请求,而是直接从缓存中加载过来。对于 firefox和safari,它们试图使这两种加载方式对用户透明,同样会引起图片的onload事件,而ie和opera则忽略了这种同一性,不会引起图片的onload事件,因此上边的代码在它们里边不能得以实现效果。
确实,在ie,opera下,对于缓存图片的初始状态,与firefox和safari,chrome下是不一样的(有兴趣的话,可以在不同浏览器下,测试一下在给img的src赋值缓存图片的url之前,img的状态),但是对onload事件的触发,却是一致的,不管是什么浏览器。产生这个问题的根本原因在于,img的src赋值与 onload事件的绑定,顺序不对(在ie和opera下,先赋值src,再赋值onload,因为是缓存图片,就错过了onload事件的触发)。应该先绑定onload事件,然后再给src赋值,代码如下:
function loadImage(url, callback) {
var img = new Image(); //创建一个Image对象,实现图片的预下载
img.onload = function(){
img.onload = null;
callback(img);
}
img.src = url;
}
这样内存泄漏,动态图片的加载问题都得到了解决,而且也以统一的方式,实现了callback的调用。
所以我使用了下面的代码:
function loadImage(url, callback) {
var img = new Image(); //创建一个Image对象,实现图片的预下载
img.onload = function(){
img.onload = null;
callback(img);
}
img.src = url;
}
或者直接采用加载多张图的方法
1.
function preloadimages(arr, callback){
var newimages=[], loadedimages=0
var arr=(typeof arr!="object")? [arr] : arr
function imageloadpost(){
loadedimages++
if (loadedimages==arr.length){
//alert("图片已经加载完成")
callback(newimages);
return;
}
}
for (var i=0; i<arr.length; i++){
newimages[i]=new Image()
newimages[i].src=arr[i]
newimages[i].onload=function(){
imageloadpost()
}
newimages[i].onerror=function(){
imageloadpost()
}
}
}
使用方法:
preloadimages(['1.gif', '2.gif', '3.gif'], function(images){
//代码块
console.log(images.length);
});
function preloadimages(arr){
var newimages=[], loadedimages=0
var postaction=function(){} //此处增加了一个postaction函数
var arr=(typeof arr!="object")? [arr] : arr
function imageloadpost(){
loadedimages++
if (loadedimages==arr.length){
postaction(newimages) //加载完成用我们调用postaction函数并将newimages数组做为参数传递进去
}
}
for (var i = 0; i<arr.length; i++){
newimages[i] = new Image()
newimages[i].src = arr[i]
newimages[i].onload = function(){
imageloadpost()
}
newimages[i].onerror = function(){
imageloadpost()
}
}
return { //此处返回一个空白对象的done方法
done:function(f){
postaction=f || postaction
}
}
}
使用方式:
preloadimages(['1.gif', '2.gif', '3.gif']).done(function(images){
alert(images.length) //alerts 3
alert(images[0].src+" "+images[0].width) //alerts '1.gif 220'
})