专业IT网络知识平台,分享IT百科知识、生活百科知识解答!

易企推科技
易企推科技

实现网页图片预加载效果的3种技术方法

来源:小易整编  作者:小易  发布时间:2022-10-14 03:58
摘要:网站开发时经常需要在某个页面需要实现对大量图片的浏览,如果考虑流量的话,大可每个页面只显示一张图片,让用户每看一张图片就需要重新下载一下整个页面。不过,在web2.0时代,更多人愿意用js来实现一个图...

网站开发时经常需要在某个页面需要实现对大量图片的浏览,如果考虑流量的话,大可每个页面只显示一张图片,让用户每看一张图片就需要重新下载一下整个页面。不过,在web2.0时代,更多人愿意用javascript来实现一个图片浏览器,让用户无需等待过长的时间就能看到其他图片。所以,对于一个网站来说,网页的预加载就显得尤为重要。在此,马海祥从网上找了3种预加载的代码,就在上跟大家分享一下,共同分析一下:

1-14050212013ML

一、常规实现图片预加载的方法

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

做过图片翻转效果的朋友其实都知道,要让图片轮换的时候不出现等待,最好是先让图片下载到本地,让浏览器缓存起来。这时,一般都会用到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);
  }
  

在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对象
   };
  };

经过这么一番折腾,总算是让各个浏览器都能满足我们的目标了。虽然代码很简单,但是却把图片浏览器中最核心的问题解决掉了,接下来你所要做的,仅仅是图片如何呈现的问题了,当然,也可以通过css来实现图片的展示效果,具体可查看的《CSS无图片技术的实现方法有哪些》,在此,我就不多说了。

二、动态图片的预加载技术

一般来说,技术人员在实现图片预加载的大体思路都是这样的:

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

马海祥觉得这个方法功能是ok的,但是有一些隐患,具体如下:

1、创建了一个临时匿名函数来作为图片的onload事件处理函数,形成了闭包。

相信大家都看到过ie下的内存泄漏模式的文章,其中有一个模式就是循环引用,而闭包就有保存外部运行环境的能力(依赖于作用域链的实现),所以img.onload这个函数内部又保存了对img的引用,这样就形成了循环引用,导致内存泄漏。(这种模式的内存泄漏只存在低版本的ie6中,打过补丁的ie6以及高版本的ie都解决了循环引用导致的内存泄漏问题)。

2、只考虑了静态图片的加载,忽略了gif等动态图片,这些动态图片可能会多次触发onload。

要解决上面两个问题很简单,其实很简单,代码如下:

img.onload = function () { //图片下载完毕时异步调用callback函数。
   img.onload = null;
   callback(img);
  };

这样既能解决内存泄漏的问题,又能避免动态图片的事件多次触发问题。

在一些相关博文中,也有人注意到了要把img.onload 设置为null,只不过时机不对,大部分文章都是在callback运行以后,才将img.onload设置为null,这样虽然能解决循环引用的问题,但是对于动态图片来说,如果callback运行比较耗时的话,还是有多次触发的隐患的。

隐患经过上面的修改后,就消除了,但是这个代码还有优化的余地:

if (img.complete) { // 如果图片已经存在于浏览器缓存,直接调用回调函数
   callback(img);
   return; // 直接返回,不用再处理onload事件
  }

关于这段代码,马海祥觉得其原因如下:

经过对多个浏览器版本的测试,发现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的调用。

三、比onload更快获取图片尺寸的预加载技术

大部分技术人员使用预加载获取图片大小的方法,基本都是通过如下的代码实现的:

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

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

当然实际中会有一些兼容陷阱,如width与height检测各个浏览器的不一致,还有webkit new Image()建立的图片会受以处在加载进程中同url图片影响,经过反复测试后的最佳处理方式:

// 更新:
  // 05.27: 1、保证回调执行顺序:error > ready > load;2、回调函数this指向img本身
  // 04-02: 1、增加图片完全加载后的回调 2、提高性能
  /**
  * 图片头数据加载就绪事件 - 更快获取图片尺寸
  * @version 2011.05.27
  * @author TangBin
  * @seehttp://www.mahaixiang.cn/wyzz/546.html
  * @param {String} 图片路径
  * @param {Function} 尺寸就绪
  * @param {Function} 加载完毕 (可选)
  * @param {Function} 加载错误 (可选)
  * @example imgReady('http://www.hkm168.com/uploads/allimg/1405/1-14050212013ML.jpg', function () {
   alert('size ready: width=' + this.width + '; height=' + this.height);
   });
  */
var imgReady = (function () {
var list = [], intervalId = null,
// 用来执行队列
tick = function () {
var i = 0;
for (; i < list.length; i++) {
list[i].end ? list.splice(i--, 1) : list[i]();
};
!list.length && stop();
},
// 停止所有定时器队列
stop = function () {
clearInterval(intervalId);
intervalId = null;
};
return function (url, ready, load, error) {
var onready, width, height, newWidth, newHeight,
img = new Image();
img.src = url;
// 如果图片被缓存,则直接返回缓存数据
if (img.complete) {
ready.call(img);
load && load.call(img);
return;
};
width = img.width;
height = img.height;
// 加载错误后的事件
img.onerror = function () {
error && error.call(img);
onready.end = true;
img = img.onload = img.onerror = null;
};
// 图片尺寸就绪
onready = function () {
newWidth = img.width;
newHeight = img.height;
if (newWidth !== width || newHeight !== height ||
// 如果图片已经在其他地方加载可使用面积检测
newWidth * newHeight > 1024
) {
ready.call(img);
onready.end = true;
};
};
onready();
// 完全加载完毕的事件
img.onload = function () {
// onload在定时器时间差范围内可能比onready快
// 这里进行检查并保证onready优先执行
!onready.end && onready();
load && load.call(img);
// IE gif动画会循环执行onload,置空onload即可
img = img.onload = img.onerror = null;
};
// 加入队列中定期执行
if (!onready.end) {
list.push(onready);
// 无论何时只允许出现一个定时器,减少浏览器性能损耗
if (intervalId === null) intervalId = setInterval(tick, 40);
};
};
})();

调用例子:

imgReady('http://www.google。com.hk/intl/zh-CN/images/logo_cn.png', function () {
   alert('size ready: width=' + this.width + '; height=' + this.height);
  });

是不是很简单?这样的方式获取摄影级别照片尺寸的速度往往是onload方式的几十多倍,而对于web普通(800&times;600内)浏览级别的图片能达到秒杀效果。看了这个再回忆一下你见过的web相册,是否绝大部分都可以重构一下的。

点评:

预加载图片是一个很好提升用户体验的小激情,以及让自己的网站看起来更专业的一个途径,进度条可以让用户知道加载的进展,避免用户的冷落感,这也能显著提升你的网站形象。


本文地址:营销网站建设频道 https://www.hkm168.com/web-yxwz/699095.html,易企推百科一个免费的知识分享平台,本站部分文章来网络分享,本着互联网分享的精神,如有涉及到您的权益,请联系我们处理,谢谢!


营销网站建设
小编:小易整编
相关文章相关阅读
  • 实用Word技巧分享:2招轻松解决多图片排版!

    实用Word技巧分享:2招轻松解决多图片排版!

    多图片排版,是Word编辑文档时常见场景之一,几乎每个人都会碰到,对很多人来说仍然是一大难题。当图片数量一多,很多人都不知道图片该怎么摆放,如何快速高效地搞定一组图片?因为没有掌握系统的套路技巧,每次制作都花费大量时间,做不出满意的效果。今...

  • 奇异值分解(SVD)简介及其在图片压缩中的示例

    奇异值分解(SVD)简介及其在图片压缩中的示例

    奇异值分解(SVD)是一种用于矩阵分解的方法。它将一个矩阵分解为三个矩阵的乘积,分别是左奇异向量矩阵、右奇异向量矩阵和奇异值矩阵。SVD在数据降维、信号处理、推荐系统等领域广泛应用。通过SVD,我们可以将高维数据降低到低维空间,从而提取出数...

  • css设置网页字体

    css设置网页字体

    css是层叠样式表的缩写,是用于网站样式设计的语言。其中,设置网页字体是css中的一个重要方面。如何使用css设置网页字体,将为我们带来更好的视觉体验,提升页面的可读性和专业感。本文将主要介绍css中的字体相关设置,包括字体样式、字体大小以...

  • Javascript如何使网页跳转

    Javascript如何使网页跳转

    方法:1、使用_window.location.href方式;2、使用window.history.back方式;3、使用window.navigate方式;4、使用self.location方式;5、使用top.location方式。本教...

  • 使用ps编辑后的图片怎么保存

    使用ps编辑后的图片怎么保存

    AdobePhotoshop,简称“PS”,是由AdobeSystems开发和发行的图像处理软件,可以有效地进行图片编辑工作。下面我们来看一下PS保存图片的方法。1、编辑完成后,单击“文件”,点击“存储为”,2、在弹出的对话框中先选...

  • html图片显示不出来怎么办

    html图片显示不出来怎么办

    在网页制作中,经常会涉及到插入图片的操作,但有时候我们会发现图片无法显示出来。这可能是因为图片链接错误、图片文件损坏或网页代码错误等原因。本文将带您了解html图片无法显示的原因和解决方法。一、图片链接错误在HTML中,图片通常通过img标...

  • 利用CSS实现图片展示特效的技巧和方法

    利用CSS实现图片展示特效的技巧和方法

    利用CSS实现图片展示特效的技巧和方法无论是网页设计还是应用开发,图片展示都是非常常见的需求。为了提升用户体验,我们可以利用CSS来实现一些炫酷的图片展示特效。本文将介绍几种常用的技巧和方法,并提供相应的代码示例,帮助读者快速上手。一、图片...

  • 网页中最基本的元素是什么

    网页中最基本的元素是什么

    网页中最基本的元素是“文字和图像”。网页是构成网站的基本元素,是承载各种网站应用的平台;而文字与图像是构成一个网页的两个最基本的元素,文字就是网页的内容,图像就是网页的美观;除此之外,网页的元素还包括动画、音乐、视频等等。网页是构成网站的...

  • 周排行
  • 月排行
  • 年排行