jQuery页面滚动图片等元素动态加载实现

这篇文章发布于 2010年11月19日,星期五,17:36,归类于 jQuery相关。 阅读 538735 次, 今日 43 次 150 条评论

 

一、关于滚动显屏加载

常常会有这样子的页面,内容很丰富,页面很长,图片较多。比如说光棍节很疯狂的淘宝商城页面。
或者是前段时间写血本买了个高档耳机的京东商城页面,或者是新浪微博之类。

这些页面图片数量多,而且比较大,少说百来K,多则上兆。要是页面载入就一次性加载完毕。乖乖,估计黄花都变成黄花菜了。所以,我们得做点什么,避免这种糟糕的状况发生。目前很流行的做法就是滚动动态加载,显示屏幕之外的图片默认是不加载的,随着页面的滚动,这个要显示图片的区域进入了浏览器可是窗口范围,则触发图片的加载显示。这种做法的好处是,一是页面加载速度快(浏览器转啊转的圈圈或是进度条很快就玩完了),二是节约了流量,因为不可能每个用户浏览页面时从头滚到尾的。

貌似我上面提到的几个站点就是采用的这种做法,例如,我以迅雷不及掩耳的速度从淘宝商城首页截下来的已触发滚动加载但是未加载完毕的图片:
淘宝商城图片滚动加载截图 张鑫旭-鑫空间-鑫生活

这是提高前端性能,优化页面加载速度很实用的做法。看上去这种技巧有些技术门槛,其实很简单的。我们需要一个滚动事件,然后判断元素是否在浏览器窗口,然后,显示图片(或是其他元素)就可以啦。我在jQuery库下写了个实现此效果的插件,下面就将简单展示讲解此插件的使用以及滚动动态加载的实现。

二、jQuery滚动加载插件scrollLoading

虽然只有几十行代码,但是为了方便使用,我还是将其插件化了。插件名为jquery.scrollLoading.js,您可以狠狠地点击这里下载(右键 – [目标|链接]另存为),或是点击这里下载mini压缩版的。

demo
您可以狠狠地点击这里:jQuery滚动加载图片等demo,如果您的网速是在贫困线上挣扎,可以慢慢拖动滚动条,就可以很清楚的看到滚动加载的效果了;如果您的网速让你引以为豪,哥,你需要很快的拖动滚动条才能瞥见效果。效果类似下面:
滚动加载demo页面效果截图 张鑫旭-鑫空间-鑫生活

demo页面中似乎有段破坏和谐的HTML片段,那是动态加载HTML后的效果,也就是说,此scrollLoading不仅可以用来滚动加载图片,Ajax load页面什么的也是可以的。

三、scrollLoading使用

不管怎样,首先调用jQuery库文件,还有jquery.scrollLoading.js,您可以直接在页面的某处添上如下的代码:

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.1/jquery.min.js"></script>
<script type="text/javascript" src="http://www.zhangxinxu.com/study/js/mini/jquery.scrollLoading-min.js"></script>

此插件的方法名就是scrollLoading,所以,直接:包装器.scrollLoading();就可以实现滚动加载效果了,简单的吧。如下:

$(".scrollLoading").scrollLoading();

表示所有class为scrollLoading的元素绑定了滚动加载的方法。
当然,不可能真的就如此简单,我们还需要做点小动作的。元素默认是不加载的,那么真正的加载地址显然要预先在元素上放置的,例如新浪微博默认把头像地址绑在了一个自定义的”dynamic-src”属性上,见下图:
新浪微博绑定真实图片地址自定义属性 张鑫旭-鑫空间-鑫生活

在HTML5中,以data-开头的自定义属性都是合法的,且地址可以是图片,页面等。所以,我设定了绑定地址的自定义属性为”data-url”,此属性值设为真实的图片(或页面)地址就可以了。例如下面:

<div class="scrollLoading" data-url="loaded.html">加载中...</div>

会在滚动时加载名为loaded.html的页面,并自动替换里面的内容。

对于常用的图片,还有一点小问题,就是其默认的src图片地址。其src地址不能是真实的图片地址(否则会直接一次性全部加载),也不能是空地址或是坏地址,否则IE浏览器下会出现很惊悚的红叉叉。IE浏览器下的红叉叉 张鑫旭-鑫空间-鑫生活。我的做法是默认链接的是一个1px * 1px的gif透明图片(大小很小),同时可以透出后面加载中gif动画图片,当滚动加载的时候直接把此gif图片替换掉。于是,对于图片,可能就有类似下面的代码:

<img class="scrollLoading" data-url="http://image.zhangxinxu.com/image/study/head/s180/1.jpeg" src="http://www.zhangxinxu.com/study/image/pixel.gif" width="180" height="180" style="background:url(http://www.zhangxinxu.com/study/image/loading.gif) no-repeat center;" />

四、scrollLoading可选参数

scrollLoading是个很简单很小的插件(无注释YUI compressor min版仅508B),所以参数也很少,就一个(已更新),见下表:

参数 默认 释义
attr data-url 获取元素加载地址的属性名

就这些了。此插件只适用于页面默认滚动条的动态加载。对于内部div之类的滚动加载不支持。更新于2012年9月27日:
根据部分同行的要求,现增加两个可选参数,一个为container表示容器,另一个为callback表示回调。具体参见下表:

参数 默认 释义
attr data-url 获取元素加载地址的属性名
container $(window) 滚动的容器。默认为$(window),也就是默认的网页滚动。
callback $.noop 回调。元素动态加载完毕后执行的回调函数。其中回调函数的上下文this就是当前DOM元素。注意:如果无法获取元素加载地址,则不执行动态加载,但是会触发回调。在某些需求下,您可以缺省url值,仅仅触发回调。

特意做了个containercallback参数使用的demo,您可以狠狠地点击这里:普通div元素中的动态滚动加载demo

新demo中绑定JavaScript代码如下:

$(".scrollLoading").scrollLoading({
    container: $("#zxxMainCon"),
    callback: function() {
        this.style.border = "3px solid #a0b3d6";	
    }
});

五、周五,结语

要下班了,nice!
明天周末,我要去钓鱼。
我感冒了,鼻涕流个不停,难受。
空间近日升级了,20G的月流量已经挺不住了。
最近经常看动漫。
我决定在RSS里面加点广告,评论链接什么的。

//zxx:主人,这是你有屎以来最龌龊的结语了。

恩,对此我举双脚表示赞同。

(本篇完)

分享到:


发表评论(目前150 条评论)

  1. zakkye说道:

    post = o.offset().top – contop, post + o.height();
    请问这里 post + o.height() 的作用

  2. wenwen说道:

    js动态加载上来生成的图片可以用吗?

  3. zuidaima说道:

    该插件遇到加载大图,上下多次滚动的话会导致同一个图片多次加载。

  4. 水中月明说道:

    测试了一下,发现callback的调用只是在触发了src的切换的时候进行,而不是在整个img的图片切换,并且新图片加载完成之后进行的。不知道能不能实现这样的功能

  5. imgiant说道:

    赞。之前使用lazyload.js.但是不知道为何该插件在IE6-8中均无法奇效。而在IE9,其他浏览器中均可正常工作。鑫鑫有时间可否研究一下?期待您的回复。

    • dodio说道:

      lazyload 就是坑爹的。
      性能低,在不设置像博主这样改变元素原地址的情况下,会触发对服务器的两次请求。
      很坑。

  6. 80后奔三ING说道:

    请问,这个动态加载进来的html页面里,如果当前页面有要执行的JS效果在上面。会顺利执行么??

  7. 突然的自我说道:

    不错,东西就是要分享

  8. hytino说道:

    这个会不会影响SEO呢???
    蜘蛛看到的所有图片都只是src=”http://www.zhangxinxu.com/study/image/pixel.gif”
    全部一样的!!

  9. jie说道:

    请问我页面是gb2312编码的话,这个图片显示无效哦??得如何改才可以呢?
    现在是utf-8编码才行。。如何支持gb2313?

  10. 小逸说道:

    我放入到自己写的焦点图里面 动态加载的时候只加载第一张图片 剩下的不加载
    是不是不合适焦点图

  11. jleung说道:

    你好,能提供一份该插件V1.1版的文件吗?就是2012-01-13版的,感谢

  12. Keen说道:

    插件里是不是忘了给posb赋值
    post = o.offset().top – contop, post + o.height();
    // post = o.offset().top – contop, posp = post + o.height();
    插件挺实用的,试着写了一遍,谢谢分享

  13. nobody说道:

    不会用啊!

  14. www说道:

    发现个问题,ajax动态载入的内容上,无法起作用。

  15. qf说道:

    因为现在只加载了屏幕看到得的图片,当用户滚动后再加载图片,用户会有等待新图片加载的时间,这个体验不好。

    可以让让图片预先加载一些么,比如屏幕下方400像素内的也先加载出来,类似 lazyload的threshold参数

  16. 暗夜说道:

    为什么我首页使用这种效果,网页底部的总数始终加载不了要显示的图片啊,上面都正常,就是最底面的数据没办法显示。求解啊??

    • 事理说道:

      将这一段代码注释掉就行了,在iframe自动高度的框架中,会导致你说的问题
      /*!if ((post >= 0 && post 0 && posb <= contHeight)) {*/

  17. 建材资讯说道:

    挺好用的,刚才试过了,成功哦也~

  18. ada说道:

    有没有什么办法解决图片不存在的话,其他的图片照常显示

  19. ada说道:

    为什么图片不存在的话,其他的图片就不加载了,不显示了

  20. KanCBA说道:

    学习了,谢谢前辈分享!

  21. 迷宫说道:

    嗯。终于让我找到了。我就是要这个,一直想实现这个效果,但是找了好久才在你这里找到。谢谢分享。

  22. ruimingde说道:

    如果站点时嵌到iframe的话,这个插件就会一次性把图片都加载出来,楼主可以试下

  23. yy说道:

    菜鸟我,不过看了那么多的留言,我决定试试效果怎么样,,,,,悲催了不懂怎么写

  24. 飞扬说道:

    下载试下。希望有帮助。谢谢

  25. linjw说道:

    好文章 很受用 我得狠狠的谢谢你,也得狠狠的支持你!

  26. Ge说道:

    楼主发表的东西都很受用啊。。。有个问题,当放的不是 jpg,而是 某些gif的半透明图,就会把 背景的 loading 也显示出来的情况。这个有什么办法解决呢? 难道也用jquery把背景去掉?

  27. shw说道:

    scrollLoading针对页面隐藏属性的div(hidden)切换或滚动图片scroll时,无法加载图片,这个问题大家有碰到吗?该怎么解决呢?

  28. ze说道:

    //动态显示数据
    var loading = function() {

    setInterval(function(){//如果用户很快的拖动滚动条的话可以避免
    var st = $(window).scrollTop(), sth = st + $(window).height();
    $.each(params.cache, function(i, data) {
    var o = data.obj, tag = data.tag, url = data.url;
    if (o) {
    post = o.offset().top; posb = post + o.height();
    if ((post > st && post st && posb < sth)) {
    //在浏览器窗口内
    if (tag === "img") {
    //图片,改变src
    o.attr("src", url);
    } else {
    o.load(url);
    }
    data.obj = null;
    }
    }
    });
    return false;

    } , 3000);
    };

    setInterval(function(){} , 3000);
    //如果用户很快的拖动滚动条到底部或者其他地方,这个方法可以避免快速加载滚动条
    我也是菜鸟,虽然实验效果成功,但还是想请教你这样作有没什么不妥或者需要优化的地方。

  29. palgerrard说道:

    每次看完大神的文章,我都忍不住要狠狠的点一点广告~~

  30. 回复说道:

    我他妈狠狠的看了,然后狠狠的下载,接着狠狠的感谢一下!!!

  31. sxrczx.com说道:

    @bravecheng,是的,我也发现这样的问题,必须强制为图片或者其他元素指定一个宽度和高度,虽然从html文档渲染速度来说,指定高度会比较好,悲催的是,假如我有些图片是用户上传来的,我并不知道他的高度,或者说加载文档,我并不知道文档的真实高度,因为内容是动态的。

    这样就存在问题了,我解决好了会发上来告诉大家的。

  32. bufeiyan说道:

    看了您不少文章,听说因为流量问题您挂广告了,所以我闭上眼狠狠点了几下,算是做点贡献吧。

  33. bravecheng说道:

    很好很强大,不过我想问下楼主,用你的这个做图片延迟加载好像图片必须要定义宽度和高度,否则是不能使用的,我是在firebug中测试的,尝试了很久才发现这个问题。希望楼主帮忙解释下奥

  34. 王宁说道:

    好奇,迅雷的首页,是用这种方法延迟加载图片的么?

  35. 倡萌说道:

    第一次来,还在用lazyload

  36. LET说道:

    哥哥,你这样做 效果是达到了,SEO就惨了!收录的图片和文字 一团糟啊

  37. amhoho说道:

    这个插件总感觉不太靠谱,应该先显示主体框架,然后随着页面显示图片,并且图片不需要过多的设置,例如某站一个页面大大小小的图片有上百张,这要是都搞个标记,会累死人。
    但这种加载方式看迅雷官网的效果还算不错,用户体验会提升许多。

  38. 小东说道:

    最初在我博客相册里用了你的插件,但分页时感觉有点卡,感谢你的文章给我一点灵感,不仅可以预加载图片,还可以随着下拉滚动条预加载某几个模块,不用一次性加载完毕。

  39. linsx说道:

    你这个用css样式里的 position: relative;之后,会变无效

    另外,我一行3张图片,有70多张图片,来自不同的网站的,下拉的时候,会很卡,很慢。

    你出现这种情况吗?

    去掉这种效果,加载很快,下拉滚动条一点都不卡

  40. cc说道:

    请问下FLash能够像这样加载吗?

  41. skxc说道:

    突然想到一个问题就是后台编辑的时候不是也看不到图片了吗? 那编辑的时候只能用正则替换出来,然后保存的时候在替换成指定的格式咯!

  42. lee说道:

    如何指定 wp 文章中所有图片
    $(“.scrollLoading”)#content img(); ?!

  43. jake说道:

    淘宝都取消了lazyload 因为触摸屏很多不支持scroll事件

  44. Lain说道:

    图片不用真实地址,感觉结构有点乱了

  45. hj0654说道:

    在激动网看视频的时候发现底部有一个工具条,用起来很方便,就类似于现在你这个网站底部的这部分,能不能研究一下,然后分享给大家看看。。。期待。。。谢谢。。

  46. seri说道:

    正好需要这个东西,真好,下回去研究研究。谢谢啊

  47. ethanchen说道:

    一般除了是需要仔细阅读的文章外,我都是用google reader阅读博主的文章的,今天看到了结束语,我点进来了。不过希望不要因此取消全文rss输出。

    • lomodd说道:

      1.post = o.offset().top – contop, post + o.height();
      应该是 post = o.offset().top – contop, posb = post + o.height();
      2.这里是会让container始终无用吧
      if ($(window).get(0) === window) {
      contop = $(window).scrollTop();
      } else {
      contop = params.container.offset().top;
      }

      条件改成$(params.container).get(0) === window对么

  48. River说道:

    之前我也用jquery lazyload ,说实话效果真的不爽啊,希望有好的用户体验延迟加载很有必要,这样用户不会觉得浏览器半天没动静。在配合页面的框架分布,做到先把页面骨架和文字显示出来,再显示图片(logo的最先显示,就像Google)。这就感觉好多了呢

  49. 流年说道:

    动态设置真实地址啊!
    淘宝也是如此实现的吗?

    • 张 鑫旭说道:

      @流年 淘宝新浪都只有图片加载的例子,图片显示真实地址是没有问题的。至于页面,我也不得而知了,不同的网站采取的策略可能会有不同吧。

  50. 向晚说道:

    之前用个jquery lazyload ,这个插件有个问题,就是当快速下拉滚动条的时候,不能马上加载可视范围内的图片,而是自上而下循序地加载。这样对用户体验有些不好。
    不知道你这个插件怎么样,试试去。