再谈javascript图片预加载技术

本文深入探讨了JavaScript中图片预加载技术的应用,包括利用占位方式获取图片头部数据尺寸,实现图片快速预览和优雅加载体验。通过对比不同方法的优劣,展示了如何在不影响用户体验的前提下优化图片加载效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转载地址: http://www.blueidea.com/tech/web/2011/8335.asp


图片预加载技术的典型应用:


如lightbox方式展现照片,无疑需要提前获得大图的尺寸,这样才能居中定位,由于javascript无法获取img文件头数据,必须等待其加载完毕后才能获取真实的大小然后展示出来,所以lightbox显示的图片的速度体验要比直接输出的差很多,而本文说提到的预加载技术主要针对获取图片尺寸。


一段典型的使用预加载获取图片大小的例子:

var imgLoad = function (url, callback) {
    var img = new Image();
    img.src = url;
    if (img.complete) {
        callback(img.width, img.height);
    } else {
        img.onload = function () {
            callback(img.width, img.height);
            img.onload = null;
        };
    };
};

web应用程序区别于桌面应用程序,响应速度才是最好的用户体验。如果想要速度与优雅兼得,那就必须提前获得图片尺寸,如何在图片没有加载完毕就能获取图片尺寸?


一、结合flash加载图片,获取图片头部数据的尺寸


flash虽然很强大,但它与生俱来的缺点让人爱恨交织,加上很多移动设备不支持falsh无疑更是致命的伤,还是放弃吧。


二、在服务端保存图片尺寸数据


这里不得不提到腾讯Qzone的lightbox相册,它就是这样做的。它能在图片没有加载完全的时候就居中放大图片,速度与优雅基本兼得。不过它仍然难以避免blog插入的外链图片的问题,也只能按传统的方式加载完毕才能展示。


三、javascript通过占位方式获取图片头部数据的尺寸


十多年的上网经验告诉我:浏览器在加载图片的时候你会看到图片会先占用一块地然后才慢慢加载完毕,并且这里大部分的图片都是没有预设width与height属性的,因为浏览器能够获取图片的头部数据。基于此,只需要使用javascript定时侦测图片的尺寸状态便可得知图片尺寸就绪的状态。


实现代码:

var imgReady = function (url, callback, error) {
    var width, height, intervalId, check, div,
        img = new Image(),
        body = document.body;
    img.src = url;
    // 从缓存中读取
    if (img.complete) {
        return callback(img.width, img.height);
    };
    // 通过占位提前获取图片头部数据
    if (body) {
        div = document.createElement('div');
        div.style.cssText = 'visibility:hidden;position:absolute;left:0;top:0;width:1px;
height:1px;overflow:hidden';
        div.appendChild(img)
        body.appendChild(div);
        width = img.offsetWidth;
        height = img.offsetHeight;
        check = function () {
            if (img.offsetWidth !== width || img.offsetHeight !== height) {
                clearInterval(intervalId);
                callback(img.offsetWidth, img.clientHeight);
                img.onload = null;
                div.innerHTML = '';
                div.parentNode.removeChild(div);
            };
        };
        intervalId = setInterval(check, 150);
    };
    // 加载完毕后方式获取
    img.onload = function () {
        callback(img.width, img.height);
        img.onload = img.onerror = null;
        clearInterval(intervalId);
        body && img.parentNode.removeChild(img);
    };
    // 图片加载错误
    img.onerror = function () {
        error && error();
        clearInterval(intervalId);
        body && img.parentNode.removeChild(img);
    };
};

运行代码框:

<!DOCTYPE html> 
<html xmlns="http://www.w3.org/1999/xhtml"> 
<head> 
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
<title>img ready</title> 
<script> 
var imgReady = function (url, callback, error) {
	var width, height, intervalId, check, div,
		img = new Image(),
		body = document.body;
		
	img.src = url;
	
	// 从缓存中读取
	if (img.complete) {
		return callback(img.width, img.height);
	};
	
	// 通过占位提前获取图片头部数据
	if (body) {
		div = document.createElement('div');
		div.style.cssText = 'visibility:hidden;position:absolute;left:0;top:0;width:1px;height:1px;overflow:hidden';
		div.appendChild(img)
		body.appendChild(div);
		width = img.offsetWidth;
		height = img.offsetHeight;
		
		check = function () {
			if (img.offsetWidth !== width || img.offsetHeight !== height) {
				clearInterval(intervalId);
				callback(img.offsetWidth, img.clientHeight);
				img.onload = null;
				div.innerHTML = '';
				div.parentNode.removeChild(div);
			};
		};
		
		intervalId = setInterval(check, 150);
	};
	
	// 加载完毕后方式获取
	img.onload = function () {
		callback(img.width, img.height);
		img.onload = img.onerror = null;
		clearInterval(intervalId);
		body && img.parentNode.removeChild(img);
	};
	
	// 图片加载错误
	img.onerror = function () {
		error && error();
		clearInterval(intervalId);
		body && img.parentNode.removeChild(img);
	};
	
};
</script> 
 
<script> 
/* demo script */
window.onload = function () {
var imgUrl = 'http://www.planeart.cn/demo/imgReady/vistas24.jpg?',
	testReadyBtn = document.getElementById('testReadyBtn'),
	clsCacheBtn = document.getElementById('clsCacheBtn'),
	status = document.getElementById('status'),
	statusReady = document.getElementById('statusReady'),
	statusLoad = document.getElementById('statusLoad'),
	imgWrap = document.getElementById('imgWrap');
	
var imgLoad = function (url, callback) {
	var img = new Image();
 
	img.src = url;
	if (img.complete) {
		callback(img.width, img.height);
	} else {
		img.onload = function () {
			callback(img.width, img.height);
			img.onload = null;
		};
	};
 
};
 
testReadyBtn.onclick = function () {
	var that = this;
 
	that.disabled = true;
	status.style.display = 'block';
	statusLoad.innerHTML = statusReady.innerHTML = 'Loading...';
	imgWrap.innerHTML = '<img src="' + imgUrl + '" />';
	
	// 使用占位方式快速获取大小
	imgReady(imgUrl, function (width, height) {
		statusReady.innerHTML = 'width:' + width + '; height:' + height;
	}, function () {
		statusReady.innerHTML = 'Img Error!';
	});
	
	// 使用传统方式获取大小
	imgLoad(imgUrl, function (width, height) {
		statusLoad.innerHTML = 'width:' + width + '; height:' + height;
		that.disabled = false;
	}, function () {
		statusLoad.innerHTML = 'Img Error!';
		that.disabled = false;
	});
	
};
 
clsCacheBtn.onclick = function () {
	imgUrl += new Date().getTime();
	status.style.display = 'none';
	imgWrap.innerHTML = '';
};
 
};
</script> 
</head> 
 
<body> 
<p>文章:《<a href="http://www.planeart.cn/?p=1121">再谈javascript图片预加载技术</a>》</p> 
<p><button id="testReadyBtn">开始加载图片</button> <button id="clsCacheBtn">清空缓存</button>(如果图片加载过后,浏览器会缓存)</p> 
<div id="status" style="display:none"> 
	<p><strong>imgReady:</strong><p> 
	<p id="statusReady"></p> 
	<p><strong>imgLoad:</strong></p> 
	<p id="statusLoad"><p> 
</div> 
<div id="imgWrap"></div> 
<div style="display:none"><script src="http://s86.cnzz.com/stat.php?id=1581115&web_id=1581115" charset="gb2312"></script></div> 
</body> 
</html> 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值