JS实现图片预加载无需等待


Posted in Javascript onDecember 21, 2012

网站开发时经常需要在某个页面需要实现对大量图片的浏览,如果考虑流量的话,大可以像pconline一样每个页面只显示一张图片,让用户每看一张图片就需要重新下载一下整个页面。不过,在web2.0时代,更多人愿意用javascript来实现一个图片浏览器,让用户无需等待过长的时间就能看到其他图片。

知道了一张图片的地址,需要把它在一个固定大小的html容器(可以是div等)里边显示出来,最重要的当然是需要知道这张即将显示的图片的宽和高,然后再结合容器的宽和高,按照一定的缩放比例使图片显示出来。因此,实现图片预加载就成为图片浏览器的核心功能了。

做过图片翻转效果的朋友其实都知道,要让图片轮换的时候不出现等待,最好是先让图片下载到本地,让浏览器缓存起来。这时,一般都会用到js里边的Image对象。一般的手段无非这样:

function preLoadImg(url) { 
var img = new Image(); 
img.src = url; 
}

通过调用preLoadImg函数,传入图片的url,就能使图片预先下载下来了。实际上,这里用到的预下载功能也和这基本一致。图片预下载下来后,通过 img的width和height属性,就能知道图片的宽和高了。但是需要考虑到,在做图片浏览器功能时,图片都是实时显示的。比如你点了显示的按钮,这个时候才会调用上边类似的代码来加载图片。因此,如果你直接用img.width的时候,图片还没有完全下载下来。因此,需要用一些异步的方法,等到图片下载完毕的时候才会再对img的width和height进行调用。

实现这样的异步方法实际上不难,图片的下载完毕事件也很简单,就是简单的onload事件。因此,我们可以写出下面的代码:

function loadImage(url, callback) { 
var img = new Image(); 
img.src = url; 
img.onload = function(){ //图片下载完毕时异步调用callback函数。 
callback.call(img); // 将callback函数this指针切换为img。 
}; 
}

好了,再来写一个测试用例。
function imgLoaded(){ 
alert(this.width); 
} 
<input type="button" value="loadImage" onclick="loadImage('aaa.jpg',imgLoaded)"/>

在firefox中测试一下,发现不错,果然和预想的效果一样,在图片下载后,就会弹出图片的宽度来。无论点击多少次或者刷新结果都一样。

不过,做到这一步,先别高兴太早——还需要考虑一下浏览器的兼容性,于是,赶紧到ie里边测试一下。没错,同样弹出了图片的宽度。但是,再点击load的时候,情况就不一样了,什么反应都没有了。刷新一下,也同样如此。

经过对多个浏览器版本的测试,发现ie6、opera都会这样,而firefox和safari则表现正常。其实,原因也挺简单的,就是因为浏览器的缓存了。当图片加载过一次以后,如果再有对该图片的请求时,由于浏览器已经缓存住这张图片了,不会再发起一次新的请求,而是直接从缓存中加载过来。对于 firefox和safari,它们视图使这两种加载方式对用户透明,同样会引起图片的onload事件,而ie和opera则忽略了这种同一性,不会引起图片的onload事件,因此上边的代码在它们里边不能得以实现效果。

怎么办呢?最好的情况是Image可以有一个状态值表明它是否已经载入成功了。从缓存加载的时候,因为不需要等待,这个状态值就直接是表明已经下载了,而从http请求加载时,因为需要等待下载,这个值显示为未完成。这样的话,就可以搞定了。

经过一些分析,终于发现一个为各个浏览器所兼容的Image的属性——complete。所以,在图片onload事件之前先对这个值做一下判断即可。最后,代码变成如下的样子:

function loadImage(url, callback) { 
var img = new Image(); //创建一个Image对象,实现图片的预下载 
img.src = url; 
if (img.complete) { // 如果图片已经存在于浏览器缓存,直接调用回调函数 
callback.call(img); 
return; // 直接返回,不用再处理onload事件 
} 
img.onload = function () { //图片下载完毕时异步调用callback函数。 
callback.call(img);//将回调函数的this替换为Image对象 
}; 
};

经过这么一番折腾,总算是让各个浏览器都能满足我们的目标了。虽然代码很简单,但是却把图片浏览器中最核心的问题解决掉了,接下来你所要做的,仅仅是图片如何呈现的问题了接下来看看另外一种方法:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml"> 
<head> 
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" /> 
<title>js 实现图片预加载 加载完后执行动作</title> 
</head> 
<style type="text/css"> 
<!-- 
*html{ 
margin:0; 
padding:0; 
border:0; 
} 
body{border:1px solid #f3f3f3; background:#fefefe} 
div#loading{ 
width:950px; 
height:265px; 
line-height:265px; 
overflow:hidden; 
position:relative; 
text-align:center; 
} 
div#loading p{ 
position:static; 
+position:absolute; 
top:50%; 
vertical-align:middle; 
} 
div#loading p img{ 
position:static; 
+position:relative; 
top:-50%;left:-50%; 
vertical-align:middle 
} 
--> 
</style> 
<div id="loading"> 
<p><img src="http://www.baidu.com/img/baidu_logo.gif" /></p> 
</div> 
<script> 
var i=0; 
var c=3; 
var imgarr=new Array 
imgarr[0]="http://www.baidu.com/img/baidu_logo.gif"; 
imgarr[1]="http://img.baidu.com/img/logo-img.gif"; 
imgarr[2]="http://img.baidu.com/img/logo-zhidao.gif"; 
var Browser=new Object(); 
Browser.userAgent=window.navigator.userAgent.toLowerCase(); 
Browser.ie=/msie/.test(Browser.userAgent); 
Browser.Moz=/gecko/.test(Browser.userAgent); 
function SImage(url,callback) 
{ 
var img = new Image(); 
if(Browser.ie){ 
img.onreadystatechange =function(){ 
if(img.readyState=="complete"||img.readyState=="loaded"){ 
ii=i+1; 
callback(i); 
} 
} 
}else if(Browser.Moz){ 
img.onload=function(){ 
if(img.complete==true){ 
ii=i+1; 
callback(i); 
} 
} 
} 
img.src=url; 
} 
function icall(v) 
{ 
if(v<c){ 
SImage(""+imgarr[v]+"",icall); 
} 
else if(v>=c){ 
i=0; 
//location.replace('banner.html');//这里写自己的动作吧, 
} 
}
Javascript 相关文章推荐
Prototype使用指南之dom.js
Jan 10 Javascript
javascript与CSS复习(《精通javascript》)
Jun 29 Javascript
functional继承模式 摘自javascript:the good parts
Jun 20 Javascript
浅谈JSON中stringify 函数、toJosn函数和parse函数
Jan 26 Javascript
牛叉的Jquery——Jquery与DOM对象的互相转换及DOM的三种操作
Oct 29 Javascript
基于Jquery插件实现跨域异步上传文件功能
Apr 26 Javascript
修改jquery中dialog的title属性方法(推荐)
Aug 26 Javascript
jQuery实现的无限级下拉菜单功能示例
Sep 12 Javascript
JavaScript中常用的验证reg
Oct 13 Javascript
详解vue事件对象、冒泡、阻止默认行为
Mar 20 Javascript
Angular2使用Angular-CLI快速搭建工程(二)
May 21 Javascript
详解react、redux、react-redux之间的关系
Apr 11 Javascript
Javascript根据指定下标或对象删除数组元素
Dec 21 #Javascript
JavaScript实现统计文本框Textarea字数增强用户体验
Dec 21 #Javascript
js返回上一页并刷新代码整理
Dec 21 #Javascript
左右悬浮可分组的网站QQ在线客服代码(可谓经典)
Dec 21 #Javascript
JS弹出窗口代码大全(详细整理)
Dec 21 #Javascript
mailto的使用技巧分享
Dec 21 #Javascript
一个页面放2段图片滚动代码出现冲突的问题如何解决
Dec 21 #Javascript
You might like
如何在PHP中使用Oracle数据库(5)
2006/10/09 PHP
Apache, PHP在Windows 9x/NT下的安装与配置 (一)
2006/10/09 PHP
php除数取整示例
2014/04/24 PHP
PHP实现数组的笛卡尔积运算示例
2017/12/15 PHP
微信推送功能实现方式图文详解
2019/07/12 PHP
php post换行的方法
2020/02/03 PHP
学习jquery必备 api中英文对照的chm手册 下载
2007/05/03 Javascript
借用Google的Javascript API Loader来加速你的网站
2009/01/28 Javascript
javascript写的一个模拟阅读小说的程序
2014/04/04 Javascript
浅谈js中变量初始化
2015/02/03 Javascript
有关json_decode乱码及NULL的问题
2015/10/13 Javascript
jQuery判断浏览器并动态调整select宽度的方法
2016/03/02 Javascript
基于JS判断iframe是否加载成功的方法(多种浏览器)
2016/05/13 Javascript
jQuery修改DOM结构_动力节点Java学院整理
2017/07/05 jQuery
vue-cli开发时,关于ajax跨域的解决方法(推荐)
2018/02/03 Javascript
浅谈es6中export和export default的作用及区别
2018/02/07 Javascript
vue前后分离调起微信支付
2019/07/29 Javascript
vue+vant实现商品列表批量倒计时功能
2020/01/13 Javascript
在Vue 中实现循环渲染多个相同echarts图表
2020/07/20 Javascript
实例讲解Python中的私有属性
2014/08/21 Python
python实现根据用户输入从电影网站获取影片信息的方法
2015/04/07 Python
Python实现批量下载图片的方法
2015/07/08 Python
基于numpy中数组元素的切片复制方法
2018/11/15 Python
Pandas的read_csv函数参数分析详解
2019/07/02 Python
opencv 图像加法与图像融合的实现代码
2020/07/08 Python
Python3如何实现Win10桌面自动切换
2020/08/11 Python
HTML5 本地存储之如果没有数据库究竟会怎样
2013/04/25 HTML / CSS
html5拖拽应用记录及注意点
2020/05/27 HTML / CSS
德国的大型美妆个护电商:Flaconi
2020/06/26 全球购物
傲盾软件面试题
2015/08/17 面试题
纪律教育月活动总结
2014/08/26 职场文书
民事撤诉申请书范本
2015/05/18 职场文书
导游词之上饶龟峰
2019/10/25 职场文书
golang 实现并发求和
2021/05/08 Golang
python 办公自动化——基于pyqt5和openpyxl统计符合要求的名单
2021/05/25 Python
Android 中的类文件和类加载器详情
2022/06/05 Java/Android