五月
20

javascript 图片预加载(远程获取图片尺寸)

注:2012.04.19更新,完善对IE的支持,修复onerror在IE下不执行问题。

有时候我们需要获取图片的尺寸,以用来对图片进行位置调整、大小限制等操作,以让图片适应页面的显示。传统的方法都是利用图片onload时获取尺寸,我也在介绍我自己用的限制图片尺寸文章中介绍了这种传统方法。但是最近我在《再谈javascript图片预加载技术》这里发现作者介绍了一种更好的方法,获取的速度远远大于传统的方法。

最近更新的社交媒体连接插件的“我的最新微博”功能支持了图片的显示(如我的右边栏),我在图片的浏览方式上加上了lightbox效果,所以我也在我的社交媒体连接插件中应用这种图片预加载技术。

实现原理

大家肯定都会见到这样一种现象,那就是浏览器在加载图片时,页面上会空出与这个图片尺寸一样的空白区域,这说明此刻图片的尺寸已经可以获取出来了,但是关键是onload必须是图片完整加载完毕才会触发。而在浏览器知道图片真正尺寸前,图片的尺寸都是固定的一个初始值,所以我们可以通过循环测试比较这个值的改变来判断浏览器是否已经获取了图片的真正尺寸。


关键代码

我在社交媒体连接插件中对作者的代码进行了些许修改,现在贴出我修改后的,仅供参考,与原作者无孰优孰劣之分。

我的主要修改是更改了回调函数的调用参数调用方式(改变了回调函数的上下文执行环境为img对象,可以通过this.width使用图片尺寸,并且可以对图片进行后续的调用处理)、以及将作者的setInterval改成了setTimeout方式、判断图片加载完成加入了onreadystatechange(因为ie下img节点使用onload有些问题)。

   1: var imageReady=(function(){
   2:     var list=[],
   3:         timer=null,
   4:         prop=[['width','height'],['naturalWidth','naturalHeight']],
   5:         natural=Number(typeof document.createElement('img').naturalHeight==='number'),//是否支持HTML5新增的 naturalHeight
   6:         tick=function(){
   7:             for(var i=0;i<list.length;i++){
   8:                 list[i].end?list.splice(i--,1):check.call(list[i],null);
   9:             }
  10:             list.length && (timer=setTimeout(tick,50)) || (timer=null);
  11:         },
  12:         /** overflow: 检测图片尺寸的改变
  13:           *  img.__width,img.__height: 初载入时的尺寸
  14:           */
  15:         check=function(){
  16:             if(this[prop[natural][0]]!==this.__width || this[prop[natural][1]]!==this.__height || this[prop[natural][0]]*this[prop[natural][1]]>1024){
  17:                 this.onready.call(this,null);
  18:                 this.end=true;
  19:             }
  20:         };
  21:         return function(_img, onready, onload, onerror){
  22:             onready=onready || new Function();
  23:             onload=onload || new Function();
  24:             onerror=onerror || new Function();
  25:             var img=typeof _img=='string'?new Image():_img;
  26:             img.onerror=function(){// ie && ie<=8 的浏览器必须在src赋予前定义onerror
  27:                 onerror.call(img,null);
  28:                 img.end=true;
  29:                 img=img.onload=img.onerror=img.onreadystatechange=null;
  30:             }
  31:             if(typeof _img=='string') img.src=_img;
  32:             if(!img)return;
  33:             if(img.complete){
  34:                 onready.call(img,null);
  35:                 onload.call(img,null);
  36:                 return;
  37:             }
  38:             img.__width=img[prop[natural][0]];
  39:             img.__height=img[prop[natural][1]];
  40:             img.onready=onready;
  41:             check.call(img,null);
  42:             img.onload=img.onreadystatechange=function(){
  43:                 if(img&&img.readyState&&img.readyState!='loaded'&&img.readyState!='complete'){return;}
  44:                 !img.end && check.call(img,null);
  45:                 onload.call(img,null);
  46:                 img=img.onload=img.onerror=img.onreadystatechange=null;
  47:             }
  48:             if(!img.end){
  49:                 list.push(img);
  50:                 if(timer===null) timer=setTimeout(tick,50);
  51:             }
  52:         }
  53: })();
  54:  
  55:  
  56: /* 使用方式
  57:  *  以此图片节点为例:<img id="preload" src="http://wwww.qiqiboy.com/preload.jpg" alt="preload" />
  58: */
  59: imageReady(document.getElementById('preload'),function(){
  60:     console.log('onready');
  61: },function(){
  62:     console.log('onload');
  63: },function(){
  64:     console.log('onerror');
  65: });
  66:  
  67: /* 在调用函数中使用图片尺寸, 调用函数中的this指向preload图片对象 */
  68: imageReady(document.getElementById('preload'),function(){
  69:     console.log('preload image width: '+this.width+'px, height: '+this.height+'px');
  70: })
  71:  
  72: /* 也可以直接使用url */
  73: imageReady('http://wwww.qiqiboy.com/preload.jpg',function(){
  74:     console.log('preload image width: '+this.width+'px, height: '+this.height+'px');
  75: })

demo还是看原作者的吧:点此

我会在社交媒体连接插件Social Medias Connect 的V1.5.6中将图片预加载方式替换为此种方式。

imgready

本文标签: , , , , ,

分享

本文短网址: http://qiqi.boy.im/et

这篇文章已经有 32 条评论

Comments (26) Trackbacks (6)
You can leave a response or Trackback this entry .
  1. liuqiqi -#1

    美美的沙发。。。 :smile:

  2. m -#2

    我勒个去…自沙了!!

  3. QiQiBoY -#3

    @m
    已经四肢bia凉bia凉的了、、、

  4. 无冷 -#4

    js神码的还是需要漫漫来看的

  5. IM路人 -#5

    这东西还是需要静下来慢慢研究~~~

  6. 设计失控 -#6

    纯表支持,我喜欢这个插件呵!这里也谢谢博主的热心相助!

  7. 推拉移门 -#7

    我也来学习了,嘿嘿

  8. elaphent -#8

    代码好长,慢慢看 :smile:

  9. 山头人 -#9

    再出个插件吧,给偶们的WP用

  10. zwwooooo -#10

    原生js我真看不懂,只能需要时直接cp用

  11. Chene -#11

    我想知道和lazyload有什么区别.虽然名字看上去差别很大

  12. wmtimes -#12

    很牛XX的学问。对于这些高深的知识了解下就行我了。

  13. 黄金岛记牌器 -#13

    现在只要能直接使用就好。

  14. mmm -#14

    img&;&img
    这里是不是弄错了叱?

  15. tl1689 -#15

    搞错了吧

  16. tl1689 -#16

    把我的评论删了?
    这一行”if(img&;&img.readyState&&img.readyState!=’loaded’”确认没有搞错吗?

  17. Kayo -#17

    很复杂的原生js,得好好研究了!

  18. jucelin -#18

    上次在哪也看到关于图片预加载技术的,看起来听吃力的。

  19. 听他 -#19

    终于找到了。- -

  20. furk -#20

    这个确实很强大

  1. 流体布局(二)

    [...] 固定宽度的流体布局的个人思路:参考文献:@qiqiboy javascript 图片预加载 [...]

  2. 流体布局插件:Waterfall

    [...] 固定宽度的流体布局的个人思路:参考文献:@qiqiboy javascript 图片预加载  [...]

  3. 流体布局插件:Waterfall

    [...] 固定宽度的流体布局的个人思路:参考文献:@qiqiboy javascript 图片预加载  [...]

  4. 终极完美版javascript获取并限制调整图片尺寸

    [...] 请参见最新的《 javascript 图片预加载》。====================================== [...]

  5. 【JavaScript温故知新】获取远程图片的尺寸大小

    [...] 请参见最新的《javascript 图片预加载 》 [...]

  6. jQuery流体布局插件:Waterfall

    [...] 固定宽度的流体布局的个人思路:参考文献:@qiqiboy javascript 图片预加载  [...]

Leave a Reply

Hi , say something.

  • :?:
  • :razz:
  • :sad:
  • :evil:
  • :!:
  • :smile:
  • :oops:
  • :grin:
  • :eek:
  • :shock:
  • :???:
  • :cool:
  • :lol:
  • :mad:
  • :twisted:
  • :roll:
  • :wink:
  • :idea:
  • :arrow:
  • :neutral:
  • :cry:
  • :mrgreen: