使用 ScrollLoading 替代 LazyLoad 实现真正的延迟加载

提示:本文参考自 CNBLOGS、鑫空间(我们所使用的插件 ScrollLoading 即由大牛@张鑫旭制作)。

什么是 LazyLoad?

大家的博客或多或少都会有一些图片,当一个页面上图片过多时,网页加载会变慢,而且服务器压力也会增大。所以,一般地,我们使用 jQuery 插件 LazyLoad 来使图片实现延迟加载。但是,iEdon 注意到一些大牛发现 LazyLoad 其实是伪延迟加载,并不能达到真正的效果。

真相:

百度搜索“图片分屏加载”,映入眼帘的就是jquery.lazyload,相信很多人用过,或许现在还在用,今天我就来说说这个插件的严重BUG。

何为图片分屏加载?顾名思义,就是让图片出现在浏览器可视区域内时,才进行加载。好处就是当页面上图片过多时候,不需要一次性加载完,大大提高了友好性,也减轻的服务器的压力。

我们发现,第一屏内的图片,是正常加载了,当滚动到第二张的时候,过了几秒,也渐显出来了,似乎没什么大问题。这时,我们用火狐的firebug再来观看下,当然为了确保测试稳定,我用金山卫士清空了浏览器缓存。

LazyLoad 无效 1

看到了么?说好的分屏加载的效果呢?怎么还是有2个请求。第一屏就一张图片,但实际上已经把两张图片都加载好了。坑爹的还不仅如此,我们继续看,当我把滚动条滑动到第二张图片……

LazyLoad 无效 2

纳尼?第三个请求出现了!!!我一共两张图片,用了jquery.lazyload居然要下载3张,不仅没有减轻服务器压力,反而增加了,这不明摆着坑爹嘛。

之后,我看了下lazyload的源码,其实逻辑上都是OK了,把img的src里的值,存放到自定义的original属性里,当图片滚动到浏览器可视区域内时,再把original里的值赋回到src里,实现分屏加载。

但问题就出在调用上,lazyload的调用方法是写在$().ready(function(){});里,如:

$().ready(function(){
	$("#tujie img").lazyload({
		effect : "fadeIn",
		failurelimit : 5
	});
});

也就是在页面载入完毕后才调用lazyload,而页面载入完毕后,图片也都下载好了,再去使用 LazyLoad 已经没有必要,反而就会出现上面说的那种情况:一共只有2张图片,却向服务器请求了3次,下载了3张图片,适得其反。

网上有篇修改 jquery.lazyload 的文章,大家可以搜搜,不过我试了下,还是不行,直接不加载了。

关于这问题的解决方法,就是换插件,iEdon 找到另一个分屏加载的插件,叫:jquery.scrollLoading。这个插件真正实现了图片分屏加载。

使用 ScrollLoading:

虽然只有几十行代码,但是为了方便使用,我还是将其插件化了。插件名为 jquery.scrollLoading.js,您可以狠狠地点击这里 下载(右键 – [目标|链接]另存为)。使用 ScrollLoading 还有一个好处,它不仅支持图片延迟,也支持资源延迟(诸如 HTML)。

首先确保你的主题使用了 jQuery,移除 LazyLoad 可能因主题不同而造成差异,这里不做阐述。

在你的主题 header.php 或 footer.php 里面加入:

<script type="text/javascript" [src="将下载的JS上传到你的服务器上后的地址"]></script>   <!-- 自行替换中括号内的内容 -->

然后在主题JS或者是直接在HTML中嵌入。

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

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

表示所有class为scrollLoading的元素绑定了滚动加载的方法。
当然,不可能真的就如此简单,我们还需要做点小动作的。元素默认是不加载的,那么真正的加载地址显然要预先在元素上放置的,例如新浪微博默认把头像地址绑在了一个自定义的”dynamic-src”属性上,见下图:
SinaLazyLoad
在HTML5中,以data-开头的自定义属性都是合法的,且地址可以是图片,页面等。所以,我设定了绑定地址的自定义属性为”data-original”(在 ScrollLoading 中可以修改自定义属性名称),此属性值设为真实的图片(或页面)地址就可以了。例如下面:

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

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

<img class="scrollLoading" [data-original="http://yourdomain/real.png"] [src="http://yourdomain/lazyloadreplace.gif"] />  <!-- 自行替换中括号内的内容 -->

在 WordPress 中,我们可以修改 functions.php 以及其他调用图片的地方,将属性  src  改为 data-original,并新增一个替代的 src  属性指向延迟加载的 Loading 动画。这里不做阐述,因为这个方法已经烂大街。

附录:ScrollLoading 可选参数

ScrollLoading 是个很简单很小的插件,所以参数也很少,见下表:

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

一个完整的使用 DEMO:

$(".scrollLoading").scrollLoading({
    container: $("#zxxMainCon"),
    callback: function() {     // 我们也可以省略回调,WP用户一般不需要
        this.style.border = "3px solid #a0b3d6";	
    }
});

最后,能好好利用 ScrollLoading,就会给你的访客、服务器带来巨大的利处。iEdon 推荐大家使用 ScrollLoading。使用效果可以参考 iEdon Inside。


54 responses to “使用 ScrollLoading 替代 LazyLoad 实现真正的延迟加载”

  1. 以后弄个玩玩。。(图片亮了)

    1. 好基友,不知怎地,越来越爱你啦 😆

  2. 可惜基于Node.js的博客系统无法使用。

  3. 顶上这个动画好高大上

    1. 就是普通的CSS动画呀,话说你终于有时间来逛逛了呀。

      1. soga,原来是两个animation,没注意。

        1. 用这个发现了ie存在渲染bug,只有一个动画在动。用ie开发人员工具把动画勾勾去掉再勾上就正常了

  4. 另外,我怎么记得lazyload有个插件,是把所有img的src属性替换掉

    1. 我记得是通过主题functions.php中加钩子,给img进行属性替换的。如果是基于js,那么网页还是会全部加载下来。

      1. 加hook,然后wctc缓存。

        1. 太高级,用不起????

  5. 图片中的字体挺好看的

    1. 我叫不出名字来,不过这些字体经常在一些教辅封面上看到。

  6. 这个有用,记录下来回去玩玩!

    1. 哈哈,不过这个还是很折腾的!

  7. 文章够长的,没耐心看下去了。。。

    1. 不长啊,试试你有没有耐心吧META的那篇看完 😛

      1. 一样不行啊

      2. 你应该去锻炼毅力了 😯

  8. 已查水表 Avatar
    已查水表

    效果不错哦~

  9. 你好,可以贴出在fun中添加的代码吗?

    1. 好的,自动添加 data-original 的代码应该是这样(网上流传的方法有误):

      //懒羊羊帮你加载图片
      function lazyload($content) {
          $loadimg_url=get_bloginfo('template_directory').'/images/lazyload.gif';
          if(!is_feed()||!is_robots()) {
              $pattern ='';
              $replacement = 'img${1}data-original="${2}" src="'.$loadimg_url.'"${3}';
              $content = preg_replace($pattern, $replacement, $content);
          }
          return $content;
      }
      1. 十分感谢你的回复。

      2. 测试了三次还是不能加上class 。。。

        1. 有没有安装钩子 (add_action)?如果没有,那么这个函数无法起作用。

  10. 有空试试你的这段代码,我站现在用的lasyload,刚看了以下好像还真有你说的这种情况。

Leave a Reply to FROYO Cancel reply

Your email address will not be published. Required fields are marked *