图片预加载方式

提升用户体验之道:图片预加载

发布于2011年04月8日,归属于javascript教程 ,jquery ,前端19个座位已被强势霸占! 共有1,226人围观    

随着网站构建越来越倾向于实现“桌面般的体验”,网站中的图片数量也开始显著地增长。想想网站中的对话框、Tabs、Tooltips、Sliders以及日历控件吧,这都是实现“桌面般体验”的必要元素。

预加载这一堆图片对网站性能及可用性的提升是有好处的,这样避免了图片加载过程中页面的闪烁、破裂(视觉上)等问题。

常用的技术

有两种常用的图片预加载技术:

CSS sprites

CSS sprites技术可以用来减少页面产生的HTTP请求数。它是这么实现的,把所有的图型状态(比如按钮的默认状态,悬停及激活等状态)保存到一张图片中。并依据元素的状态,使用CSS对图片进行相应的定位、切割。

不过这样有个重要的缺点——需要提前加载的图片不适用这项技术。一些后面才需要显示的图片并没有被加载,这可能会导致一个延迟。因此,此技术一般适合静态站点,主要用来减少图片加载数。

JavaScript

另一个可以使用的技术是使用JavaScript的image对象。这个方法是这样的,先把网站中使用的每个图片的地址(URL)放到一个数组中。

  1. varmyImages = ["image_1.jpg', 'image_2.jpg', 'image_3.jpg', ...];

然后遍历这个数组,根据图片地址创建各自的image对象。这样可以保证所有的图片都能被浏览器缓存,等用到的时候就无需等待了。

  1. for(vari = 0;i <= myImages.length;i++){
  2.      var img =new Image();
  3.      img.src =myImages[i];
  4. }

此方案费时的地方是,不仅要制造一个包含每张图片地址的数组,还要维护它的一致性。网站的每个需求变更(添加或更改图片地址)都会影响到这个数组。试想频繁变更的应用,又拥有数百张图片,这真会让人筋疲力尽的。

图片自动预加载(带进度指示器)

一个更好的方式是自动收集图片的地址。

首先要分析页面中(包括外链及内联)的样式表。这可以通过遍历“document.styleSheets”对象来获得页面使用的所有样式表。

  1. for(vari = 0;i < document.styleSheets.length;i++){

接下来要找出样式表的根目录。用来得到各个图片的绝对地址。

  1. varbaseURL = getBaseURL(document.styleSheets[i].href);

考虑到浏览器的兼容性,必须同时检查每个样式表的“cssRules”或“rules”中是否包含CSS规则。

  1. if(document.styleSheets[i].cssRules){
  2.     cssRules =document.styleSheets[i].cssRules
  3. }
  4. else if(document.styleSheets[i].rules){
  5.     cssRules =document.styleSheets[i].rules
  6. }

所有非空的CSS规则都要被解析,来确认它是否关联了图片。一个简单的正则表达式就可以解析出图片地址。

  1. varcssRule = cssRules[j].style.cssText.match(/[^\(]+\.(gif|jpg|jpeg|png)/g);

然后,把这里收集到的所有图片地址保存到一个数组中供后面使用。

  1. functionanalyzeCSSFiles(){
  2.     var cssRules;// CSS rules
  3.    
  4.     for (vari = 0;i < document.styleSheets.length;i++){ // loop through all linked/inline stylesheets
  5.       
  6.         var baseURL =getBaseURL(document.styleSheets[i].href);// get stylesheet's base URL
  7.  
  8.         // get CSS rules
  9.         if (document.styleSheets[i].cssRules){
  10.             cssRules =document.styleSheets[i].cssRules
  11.         }
  12.         else if(document.styleSheets[i].rules){
  13.             cssRules =document.styleSheets[i].rules
  14.         }
  15.        
  16.         // loop through all CSS rules
  17.         for (varj = 0;j < cssRules.length;j++){
  18.             if (cssRules[j].style && cssRules[j].style.cssText){
  19.                 // extract only image related CSS rules
  20.                 // parse rules string and extract image URL
  21.                 var cssRule =cssRules[j].style.cssText.match(/[^\(]+\.(gif|jpg|jpeg|png)/g);
  22.                 if (cssRule){
  23.                     // add image URL to array
  24.                     cssRule =(cssRule +"").replace("\"","")
  25.                     imageURLs.push(baseURL + cssRule);
  26.                 }
  27.             }
  28.         }
  29.     }
  30. }

数组中存放的图片地址是绝对路径,为了得到它,我们实现了“getBaseUrl”函数来解析每个CSS文件的绝对地址。

  1. functiongetBaseURL(cssLink){
  2.     cssLink =(cssLink) ?cssLink : 'window.location.href';// window.location.href for inline style definitions
  3.    
  4.     var urlParts =cssLink.split('/');// split link at '/' into an array
  5.     urlParts.pop();// remove file path from URL array
  6.    
  7.     var baseURL =urlParts.join('/');// create base URL (rejoin URL parts)
  8.    
  9.     if (baseURL !="") 
  10.     {
  11.         baseURL +='/';// expand URL with a '/'
  12.     }
  13.    
  14.     return baseURL;
  15. }

现在,遍历这个列表,为网站的每个图片创建一个JavaScript图片对象,来实现图片预加载并强制浏览器进行缓存。请注意“setTimeout”的使用,它确保了每个图片加载是依序执行的,当前图片加载完成才会加载下一个。原因是某些浏览器无法同时处理超过2个请求(译者注:IE6单域下的并发连接数限制就是2个)。为了避免可能的死锁,这里使用jQuery的bind方法给“load”、“onreadystatechange”和“error”事件绑定了一个处理器。这样可以确保遇到无法加载的遗失图片时,“errorTimer”可以把你带回正确的轨道。

  1. functionpreloadImages(){
  2.     if (imageURLs &&imageURLs.length &&imageURLs[imagesLoaded]){ // if image URLs array isn't empty
  3.         var img =new Image();// create a new imgage object
  4.         img.src =imageURLs[imagesLoaded];// set the image source to the extracted image URL
  5.        
  6.         setTimeout(function (){
  7.             if (!img.complete){
  8.                 jQuery(img).bind('onreadystatechange load error', onImageLoaded);// bind event handler
  9.             } else{
  10.                 onImageLoaded();// image loaded successfully, continue with the next one
  11.             }
  12.                        
  13.             errorTimer =setTimeout(onImageLoaded,1000);// handle missing files (load the next image after 1 second)
  14.         },25);
  15.     }
  16.     else {
  17.         showPreloadedImages();
  18.     }
  19. }
  20.  
  21. function onImageLoaded(){
  22.     clearTimeout(errorTimer);// clear error timer
  23.    
  24.     imagesLoaded++;// increase image counter
  25.    
  26.     preloadImages();// preload next image
  27. }

为了提升预加载时的用户体验,这里对“onImageLoaded”事件处理器做点改动,来添加一个进度条。

首先,引入jQuery UI的样式和显示进度条所需要的JavaScript文件。

  1. <linktype="text/css"href="css/ui-lightness/jquery-ui-1.8.6.custom.css"rel="stylesheet"/>
  2. <script type="text/javascript"src="js/jquery-1.4.2.min.js"></script>
  3. <script type="text/javascript"src="js/jquery-ui-1.8.6.custom.min.js"></script>

然后在DOMReady事件被触发时初始化进度条。

  1. $(document).ready(function() {
  2.     $("#progressbar").progressbar({ value:0 });// initialize progress bar
  3. });

最后要做的一件事是扩展“onImageLoaded”事件处理函数。每加载完一张图片,就计算一次进度并更新进度条。

为了验证预加载的效果,这里把所有图片都添加到页面中。在预加载全部完成时,所有的图片会同时显示。

  1. functiononImageLoaded(){
  2.     clearTimeout(errorTimer);// clear error timer
  3.  
  4.     $("#imagelist").append("<span>" + imagesLoaded +": </span><img src='" +imageURLs[imagesLoaded] +"'/>");// append image tag to image list
  5.  
  6.     imagesLoaded++;// increase image counter
  7.  
  8.     var percent =parseInt(100 *imagesLoaded / (imageURLs.length - 1));// calculate progress
  9.  
  10.     $("#progressbar").progressbar({ value: percent });// refresh progress bar
  11.     $("#progressbarTitle").text("Preloading progress: " + percent + "%");
  12.  
  13.     preloadImages(); // preload next image
  14. }
优秀只需一小步

预加载图片是一个提升用户体验,以及让自己的网站看起来更专业的一个途径。通过自动分析CSS规则来进行图片的批量预加载也避免了大量的体力活。

进度条可以让用户知道加载的进展,避免用户的冷落感。另外,jQuery提供了大批优秀组件,进度条就是其中一个,只需简单的配置就可以满足我们的需求。使用它们无疑能显著提升你的网站形象。

希望这篇文章能给你带来灵感,去思考你的项目是否也能从这里描述的技术受益。

最后附上zip文件,它包含所有上面的预加载示例文件。下载并解压后,用浏览器打开preloading.html,并单击“Start preloading”就可以观看示例了。

再做些简单修改,你就可以把它集成到你自己的项目里了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值