代码改变世界

图片预加载

2013-07-16 19:13  臭小子1983  阅读(611)  评论(0编辑  收藏  举报

  资源预加载可以提升用户体验,如果每次用户打开页面都要加载图片,js,css等资源,会影响用户体验。资源预加载可以一定程度上改善这种情况。

  我们可以做的是,但第一个页面load完的时候,在用户阅读网页的空隙,把下一个页面所用的资源提前加载过来cache住,这样下个页面就直接读缓存资源了,这样可以一定程度改善用户体验。

     那么预加载资源需要解决的主要问题是JS加载过来不会被直接执行,css加载过来不会更改页面样式。

 

一、Image对象的属性和方法

1、src:图片的路径

2、title:图征的

3、onload:图片载入完成后调用的事件

4、complete、readyState:图片载入成功调用的事件IE专有

 

code:

<input type="button" name="" value="载入图片" onclick="addImg('http://ossweb-img.qq.com/upload/adw/image/201307/1373323962034898366.jpg')"> 
<script type="text/javascript">
function addImg(isrc){
	var Img = new Image();
	Img.src = isrc;
	Img.onload = function (){
		document.body.appendChild(Img);
	}
}
</script>

  页面打开时并没有加载图片,当点击按钮时将图片载入进来,在ie和opera中点完一次在点就不会在出来图片是因为缓存机制

 

修改一下code:

<input type="button" name="" value="载入图片" onclick="addImg('http://ossweb-img.qq.com/upload/adw/image/201307/1373323962034898366.jpg')"> 
<script type="text/javascript">
function addImg(isrc){
	var Img = new Image();	
	Img.onload = function (){
		document.body.appendChild(Img);
	}
	Img.src = isrc;
}
</script>

这样就将问题解决了

 

二、图片预加载技术的典型应用

  如lightbox方式展现照片,无疑需要提前获得大图的尺寸,这样才能居中定位,由于javascript无法获取img文件头数据,必须等待其加载完毕后才能获取真实的大小然后展示出来,所以lightbox显示的图片的速度体验要比直接输出的差很多,而本文说提到的预加载技术主要针对获取图片尺寸。

  一段典型的使用预加载获取图片大小的例子:

 1 var imgLoad = function (url, callback) {
 2     var img = new Image();
 3     img.src = url;
 4     if (img.complete) {
 5         callback(img.width, img.height);
 6     } else {
 7         img.onload = function () {
 8             callback(img.width, img.height);
 9             img.onload = null;
10         };
11     };
12 };

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

 

三、结合flash加载图片,获取图片头部数据的尺寸

  flash虽然很强大,但它与生俱来的缺点让人爱恨交织,加上很多移动设备不支持falsh无疑更是致命的伤,还是放弃吧。

 

四、在服务端保存图片尺寸数

  这里不得不提到腾讯Qzone的lightbox相册,它就是这样做的。它能在图片没有加载完全的时候就居中放大图片,速度与优雅基本兼得。不过它仍然难以避免blog插入的外链图片的问题,也只能按传统的方式加载完毕才能展示。

 

三、javascript通过占位方式获取图片头部数据的尺

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

实现代码:

  1 <script>
  2     function getID(id){
  3         return document.getElementById(id);    
  4     }
  5 
  6     var center = getID("center");
  7     var btn = getID("btn");
  8     var cur = 0;
  9     var arr = ["http://www.miaov.com/miaov_demo/miaov-demo-2/img/image1.jpg","http://www.miaov.com/miaov_demo/miaov-demo-2/img/image10.jpg","http://www.miaov.com/miaov_demo/miaov-demo-2/img/image2.jpg","http://www.miaov.com/miaov_demo/miaov-demo-2/img/image3.jpg","http://www.miaov.com/miaov_demo/miaov-demo-2/img/image4.jpg","http://www.miaov.com/miaov_demo/miaov-demo-2/img/image5.jpg","http://www.miaov.com/miaov_demo/miaov-demo-2/img/image6.jpg","http://www.miaov.com/miaov_demo/miaov-demo-2/img/image7.j
 10 pg","http://www.miaov.com/miaov_demo/miaov-demo-2/img/image8.jpg","http://www.miaov.com/miaov_demo/miaov-demo-2/img/image9.jpg"];
 11 
 12    // 图片预加载方法
 13     function preloading(imgUrl,callback){
 14         var newImg = new Image();
 15         newImg.src = imgUrl;
 16         if (newImg.complete) {
 17             callback(newImg);
 18         }
 19         else {
 20             newImg.onload = function () {
 21                 callback(newImg);
 22                 newImg.onload = null;
 23             };
 24         };
 25 
 26         var width = newImg.offsetWidth;
 27         var height = newImg.offsetHeight;
 28         var check = function(){     // 侦听图片的头信息返回的宽、高度
 29             if(newImg.width !== width || newImg.height !== height){       // 如果宽、高度与初始不相等(相当于已获取到宽、高度)
 30                 callback(newImg);
 31                 clearInterval(intervalId);
 32                 newImg.onload = null;
 33             }
 34         }
 35         var intervalId = setInterval(check, 150);
 36     };
 37 
 38     function showImg(imgObj){
 39         var _w = imgObj.width;
 40         var _h = imgObj.height;
 41         center.innerHTML = "";
 42         miaovStartMove(center,{width:_w, height:_h},MIAOV_MOVE_TYPE.BUFFER,
 43             function(){
 44                 imgObj.style.opacity = 0;
 45                 center.appendChild(imgObj);
 46                 miaovStartMove(imgObj,{opacity:100},MIAOV_MOVE_TYPE.BUFFER);
 47             }
 48         );
 49     }
 50 
 51     btn.onclick = function(){
 52         cur++;
 53         if(cur >= arr.length){
 54             cur=0;
 55         }
 56         preloading(arr[cur], showImg);
 57     }
 58 
 59     preloading(arr[0],showImg);
 60 
 61     // 运动
 62     function css(obj, attr, value){
 63         if(arguments.length == 2){
 64             var sCur=obj.currentStyle?obj.currentStyle[attr]:document.defaultView.getComputedStyle(obj, false)[attr];
 65             if(attr=='opacity') {
 66                 return parseInt(parseFloat(sCur)*100);
 67             }
 68             else{
 69                 return parseInt(sCur);
 70             }
 71         }
 72         else if(arguments.length==3)
 73             switch(attr){
 74                 case 'width':
 75                 case 'height':
 76                 case 'paddingLeft':
 77                 case 'paddingTop':
 78                 case 'paddingRight':
 79                 case 'paddingBottom':
 80                     value=Math.max(value,0);
 81                 case 'left':
 82                 case 'top':
 83                 case 'marginLeft':
 84                 case 'marginTop':
 85                 case 'marginRight':
 86                 case 'marginBottom':
 87                     obj.style[attr]=value+'px';
 88                     break;
 89                 case 'opacity':
 90                     obj.style.filter="alpha(opacity:"+value+")";
 91                     obj.style.opacity=value/100;
 92                     break;
 93                 default:
 94                     obj.style[attr]=value;
 95             }
 96         return function (attr_in, value_in){css(obj, attr_in, value_in)};
 97     }
 98 
 99     MIAOV_MOVE_TYPE={
100         BUFFER: 1,
101         FLEX: 2,
102         FAST: 3,
103         SLOW: 4,
104         NORMAL: 5
105     };
106     function miaovStartMove(obj, oTarget, iType, fnCallBack, fnDuring){
107         var fnMove=null;
108         if(obj.timer){
109             clearInterval(obj.timer);
110         }
111 
112         switch(iType){
113             case MIAOV_MOVE_TYPE.BUFFER:
114                 fnMove = miaovDoMoveBuffer;
115                 break;
116             case MIAOV_MOVE_TYPE.FLEX:
117                 fnMove = miaovDoMoveFlex;
118                 break;
119         }
120 
121         obj.timer=setInterval(function (){
122             fnMove(obj, oTarget, fnCallBack, fnDuring);
123 
124             var now=(new Date()).getTime();
125             obj.lastMove=now;
126         }, 30);
127 
128         if(!obj.lastMove){
129             obj.lastMove = 0;
130         }
131 
132         var now = (new Date()).getTime();
133         if(now - obj.lastMove > 30){
134             fnMove(obj, oTarget, fnCallBack, fnDuring);
135             var now = (new Date()).getTime();
136             obj.lastMove = now;
137         }
138     }
139 
140     function miaovDoMoveBuffer(obj, oTarget, fnCallBack, fnDuring){
141         var bStop = true;
142         var attr = '';
143         var speed = 0;
144         var cur = 0;
145 
146         for(attr in oTarget){
147             oTarget[attr]=parseInt(oTarget[attr]);
148             cur=css(obj, attr);
149             if(oTarget[attr]!=cur){
150                 bStop=false;
151                 speed=(oTarget[attr]-cur)/5;
152                 speed=speed>0?Math.ceil(speed):Math.floor(speed);
153                 css(obj, attr, cur+speed);
154             }
155         }
156 
157         if(fnDuring)fnDuring.call(obj);
158         if(bStop){
159             clearInterval(obj.timer);
160             obj.timer = null;
161             if(fnCallBack)fnCallBack.call(obj);
162         }
163     }
164 
165     function miaovDoMoveFlex(obj, oTarget, fnCallBack, fnDuring){
166         var bStop = true;
167         var attr = '';
168         var speed = 0;
169         var cur = 0;
170 
171         for(attr in oTarget){
172             if(!obj.oSpeed)obj.oSpeed = {};
173             if(!obj.oSpeed[attr])obj.oSpeed[attr]=0;
174             cur=css(obj, attr);
175             if(Math.abs(oTarget[attr]-cur)>=1 || Math.abs(obj.oSpeed[attr])>=1){
176                 bStop=false;
177                 obj.oSpeed[attr]+=(oTarget[attr]-cur)/5;
178                 obj.oSpeed[attr]*=0.7;
179                 css(obj, attr, cur+obj.oSpeed[attr]);
180             }
181         }
182 
183         if(fnDuring)fnDuring.call(obj);
184 
185         if(bStop){
186             clearInterval(obj.timer);
187             obj.timer=null;
188             if(fnCallBack)fnCallBack.call(obj);
189         }
190     }
191 
192     function stopMove(obj){
193         clearInterval(obj.timer);
194     }
195 </script>