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 相关文章推荐
JS网页图片按比例自适应缩放实现方法
Jan 15 Javascript
jquery默认校验规则整理
Mar 24 Javascript
使用documentElement正确取得当前可见区域的大小
Jul 25 Javascript
js使用for循环与innerHTML获取选中tr下td值
Sep 26 Javascript
网站基于flash实现的Banner图切换效果代码
Oct 14 Javascript
jquery比较简洁的软键盘特效实现方法
Mar 19 Javascript
javascript实现炫酷的拖动分页
May 11 Javascript
基于Css3和JQuery实现打字机效果
Aug 11 Javascript
基于JavaScript实现文字超出部分隐藏
Feb 29 Javascript
bootstrap datepicker限定可选时间范围实现方法
Sep 28 Javascript
bootstrap table实现双击可编辑、添加、删除行功能
Sep 27 Javascript
解决vue-router 切换tab标签关闭时缓存问题
Jul 22 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
基于mysql的论坛(3)
2006/10/09 PHP
PHP缓存机制Output Control详解
2014/07/14 PHP
php上传图片获取路径及给表单字段赋值的方法
2016/01/23 PHP
php自定义函数实现JS的escape的方法示例
2016/07/07 PHP
php无限极分类实现方法分析
2019/07/04 PHP
jquery1.4 教程二 ajax方法的改进
2010/02/25 Javascript
在模板页面的js使用办法
2010/04/01 Javascript
jquery下div 的resize事件示例代码
2014/03/09 Javascript
Jquery选择器中使用变量实现动态选择例子
2014/07/25 Javascript
jQuery中 $ 符号的冲突问题及解决方案
2016/11/04 Javascript
详解JavaScript的内置对象
2016/12/07 Javascript
BootStrap 下拉菜单点击之后不会出现下拉菜单(下拉菜单不弹出)的解决方案
2016/12/14 Javascript
jQuery日程管理插件fullcalendar使用详解
2017/01/07 Javascript
Vue组件的使用教程详解
2018/01/05 Javascript
详解如何在你的Vue项目配置vux
2018/06/04 Javascript
Element-ui tree组件自定义节点使用方法代码详解
2018/09/17 Javascript
微信小程序设置滚动条过程详解
2019/07/25 Javascript
详解NodeJs项目 CentOs linux服务器线上部署
2019/09/16 NodeJs
vue项目使用高德地图的定位及关键字搜索功能的实例代码(踩坑经验)
2020/03/07 Javascript
H5+css3+js搭建带验证码的登录页面
2020/10/11 Javascript
Python的Django框架可适配的各种数据库介绍
2015/07/15 Python
详解Django缓存处理中Vary头部的使用
2015/07/24 Python
Python二分查找详解
2015/09/13 Python
Python实现base64编码的图片保存到本地功能示例
2018/06/22 Python
Python使用random模块生成随机数操作实例详解
2019/09/17 Python
Tensorflow进行多维矩阵的拆分与拼接实例
2020/02/07 Python
python计算波峰波谷值的方法(极值点)
2020/02/18 Python
python GUI库图形界面开发之PyQt5图片显示控件QPixmap详细使用方法与实例
2020/02/27 Python
Python3 用matplotlib绘制sigmoid函数的案例
2020/12/11 Python
使用数据结构给女朋友写个Html5走迷宫游戏
2019/11/26 HTML / CSS
自我鉴定的范文
2013/10/03 职场文书
C++程序员求职信范文
2014/04/14 职场文书
绘画专业自荐信
2014/07/04 职场文书
大学军训通讯稿(2016最新版)
2015/12/21 职场文书
用人单位的规章制度,怎样制定才是有效的?
2019/07/09 职场文书
mysql数据插入覆盖和时间戳的问题及解决
2022/03/25 MySQL