四月
12

JavaScript & images LazyLoad 图片延迟加载(伪lazyload)

注意,有歌声飘出,赶紧静音先!

2011.04.12 16:20更新:mice童鞋提醒,这种纯JS的图片lazyload都是自欺欺人,所以大家听歌吧,以下别看了。真正的lazyload需要前后端配合。你可以使用firebug或者chrome自带的开发者工具查看下面demo页面的资源resources或者网络,可以看到图片都是被下载下来了,并不会因为src的改变或者移除而停止加载。


lazyload可以用于很多场合,如JS、css的按需加载;对于页面上很多大图片的网站来说,图片的延迟加载,可以很好的节约页面大小,减少页面与服务器的资源交互,减少用户的等待时间等。所以使用的人越来越多了。

刚不久前做一个业务时,碰到了此类需求。不同的是,这个网站上没有引入jQuery,所以不能拿别人开发的jQuery lazyload插件来开发了。遂只好自己来写代码了,此文贴出代码,仅作参考交流。代码基本上实现了图片lazyload的需求,不过还有一些问题,如果你对代码有改进建议和意见,欢迎留言告知,先谢!

可以先看demo,再看代码。

var addListener=function(e, n, o, u){
    if(e.addEventListener) {
        e.addEventListener(n, o, u);
        return true;
    } else if(e.attachEvent) {
        e['e' + n + o] = o;
        e[n + o] = function() {
            e['e' + n + o](window.event);
        };
        e.attachEvent('on' + n, e[n + o]);
        return true;
    }
    return false;
},
getObjPoint=function(o){
    var x=y=0;
    do {
        x += o.offsetLeft || 0;
        y += o.offsetTop  || 0;
        o = o.offsetParent;
    } while (o);
    return {'x' :x ,'y':y};
},
IE=function(){
    if(/msie (\d+\.\d)/i.test(navigator.userAgent)){
        return document.documentMode || parseFloat(RegExp.$1);
    }
    return 0;
}
//上面是一些功能函数的封装,下面是lazyload部分
var lazyload=function(img){
        if(img.complete||img.readyState&&(
            img.readyState=='loaded'||img.readyState=='complete')
            ){//图片已经下载或者缓存就不用继续了
            return false;
        }
        img.setAttribute('_src',img.src);
        img.src='images/nothing.gif';
        //如果不想显示占位loading图片,也可以移除src:img.removeAttribute('src'); 
        //貌似移除src在webkit核心浏览器(safari & chrome)下并不会阻止浏览器下载图片,所以最好还是使用占位图片方式
        //但是请不要将src设置为空,img.src=""; 貌似某些浏览器下还会下载其他东西(IE?)
        var action=function(img){//响应操作
            if(img.getAttribute('loaded')){//判断是否loaded了
                clearInterval(img.timer);
                return;
            }
            var doc=document.documentElement,
                body=document.body,
                sy=(doc&&doc.scrollTop || body&&body.scrollTop || 0) - (doc&&doc.clientTop || body&&body.clientTop || 0),
                np=getObjPoint(img),
                ny=np.y,
                wy=doc&&doc.clientHeight || body&&body.clientHeight;
            //console.log(ny+'|'+sy+'|'+wy)
            if(Math.abs(ny-sy)<wy){
            //通过计算比较图片与当前浏览器窗口的位置判断图片是否已进入当前可视区域
                img.setAttribute('loaded','loaded');//设置loaded属性,标记此img已经开始加载
                img.src=img.getAttribute('_src');//修正src
                img.onload=img.onerror=img.onreadystatechange=function(){
                //IE通过onreadystatechange,其他onload
                    if(img&&img.readyState&&img.readyState!='loaded'&&img.readyState!='complete'){
                        return false;
                    }
                    img.onload = img.onreadystatechange = img.onerror = null;
                    var animat=function(el){//一个简单的fadeIn效果
                        var s=0,
                            timer=setInterval(function(){
                            el.style.opacity=s;
                            el.style.filter=('opacity='+(s*100));
                            s+=0.05;
                            if(s>1)clearInterval(timer);
                        },30)
                    }
                    animat(img);
                };
            }
        }
        action(img);
        if(IE()&&IE()<9){
        //ie8及以下浏览器通过scroll事件绑定貌似有问题,暂时先用定时器实现
            img.timer=setInterval(function(){action(img)},1000);
        }else{
            addListener(window,'scroll',function(){action(img)},false);
        }
    }

DEMO

调用代码,可以遍历需要lazyload的图片,然后循环调用lazyload(img)即可,具体可下载demo查看。

实现原理是遍历图片,判断图片是否已经加载(readyStatte)或者存在缓存(complete),如果还未加载,那么就将图片的src设置成占位图片,然后绑定事件。如果检测到图片已经进入可视区域,那么就将src再设置过来。

有一些疑问:

第一,IE下的绑定scroll事件,貌似不能多绑定,只能绑定一个,类似于使用window.onscroll了,原因不明。还未深究,暂时用setInterval替代。

第二,浏览器对图片的下载加载方式。如果图片正在下载,然后将其src设置为另外一个,那么之前的图片是会立即被abort吗?所有浏览器都是这样的?如果将src设置为空(img.src=”),那么之前的图片会被abort停止加载吗?所有浏览器都这样?移除src(removeAttibute(‘src’))呢?

如果有人有相关资料,欢迎提供。

2011.04.12 16:20 更新: 实践证明,我上面疑问的答案是 否,也就是无论你移除src或者重设src,都不能阻止浏览器(chrome、ff>4?)下载之前的图片。所以JS版的lazyload是无意义的。只有前后端配合(页面输出前就将img的src设置为占位图),才能真正lazyload。

所以大家不要再使用那个神马jquery lazyload了,毫无意义。本文代码也毫无意义。唯一的亮点,大概就是图片加载时的fadeIn效果有一些迷人吧。。。哈哈

lzyload

本文标签: , , , ,

分享

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

这篇文章已经有 46 条评论

Comments (45) Trackbacks (1)
You can leave a response or Trackback this entry .
  1. Carin -#21

    jquery的lazyload可以用,很好用,楼主你可以试试http://www.appelsiini.net/projects/lazyload/enabled.html
    不要试你自己的页面,因为jquery的lazyload和其他js代码经常会冲突,导致伪延迟

  2. GOVO -#22

    lazyLoad原主页上已说明lazyLoad对新版浏览器不再起作用,已经停止更新。对现在的浏览器来说,只要出现过,不论你是否隐藏,或者是否马上通过DOM删除,SRC里的图片都会被加载。可能迅速修改src这招对比较旧的浏览器才有用吧。

  3. GOVOq -#23

    现在官方那个已经作了一些良善,判断一下页面是否写有original,如果写有,就不变动
    /* Save original only if it is not defined in HTML. */
    if (undefined == $(self).attr(“original”)) {
    $(self).attr(“original”, $(self).attr(“src”));
    }
    但依然需要手工改img 的src

  4. miller -#24

    你好,很感谢你所提供的图片延迟加载的方式

  5. learn158 -#25

    兄弟受教了,本来以为他有多有X,原来就是这么回事,呵呵。

  6. xiaowu -#26

    在系统生成img的时候, 不要写入src属性. 写入original或者其他记录url的属性.
    页面加载的时候, 没有src属性. 浏览器也不会去加载图片了.
    等scrollevent的时候,遍历imgs, 判断坐标, 替换src为original就可以了. 根本不需要考虑现代浏览器只要有src就加载,并且不能中断加载的问题.

  7. 太原SEO -#27

    博主真是辛苦了,我用了jQuery lazyload插件,但是火狐下不支持,能给我看下吗?

  8. 黑色幽默 -#28

    楼主我怎么看见不一样的效果,图片是开始没有加载的。怎么可能没有用呢? 用这个用户体验不错。(你这不是误导别人?)

  9. 稻草刀刀 -#29

    :mrgreen:

  10. 高清电影 -#30

    jquery的lazyload是把图片地址写在data-original,而不是src

  11. 牧风 -#31

    这个插件真的没什么用

  12. bzyc -#32

    目前这个插件,已经被改进了,使用了一张图片来替换。。。所以你这文章应该撤了

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: