八月
27

JS延迟加载机制函数(Lazyload)

最近应该大家都发现了,我的博客很多模块都使用了延迟加载技术。这个延迟加载(lazyload)我第一次听说其实还是不久前,那是在别人博客看到介绍的一个基于jQuery的图片延迟加载插件。我对这个很感兴趣,其实很多网站也都应用了这个技术,尤其是大型网站,可以有效地减少服务器压力。

我原先觉得这个技术挺神秘的,实现起来应该比较困难,并且在网上也并没有找到相关的文章或者介绍。但是当我真正决定要去这样做时,却发现其实这个真的挺简单的,原理也容易理解。

lazyload,简单地说,就是在浏览器滚动到某个位置时再出发相关函数,实现页面元素的加载或者某些动作的执行。浏览器的滚动位置检测,可以通过一个定时器来循环检测,通过比较某一时刻页面目标节点位置和浏览器滚动条高度来判断需不要要执行函数。我将这个方法写成了一个类,我自己博客即是使用我的这个方法。

(下面代码纯属自己的小试手,如果有不完善地方可以指出)

   1: function Lazyload(func, obj) {//obj目标节点对象, func要触发的函数
   2:     this.func = func;
   3:     this.obj = obj;
   4:     this.it = setInterval(function() {//2s检查一次
   5:         this.checkScroll();
   6:     }.bind(this), 2000);//bind为setInterval绑定lazyload对象,否则this会指向window对象
   7: }
   8:  
   9: Function.prototype.bind = function(obj) {//对象绑定
  10:     var __method = this;
  11:     return function() { 
  12:         return __method.apply(obj, arguments); 
  13:     };
  14: }
  15:  
  16: Lazyload.prototype.checkScroll = function() {
  17:     var scrollY = document.body.scrollTop || document.documentElement.scrollTop || window.pageYOffset || 0,//页面滚动条高度
  18:         seeY = window.innerHeight||document.documentElement.clientHeight,//浏览器可视区域高度
  19:         func = this.func;
  20:     if (Math.abs(this.getY() - scrollY) < seeY) {//当目标节点进入可视区域,即页面滚动条高度减去节点距页面顶部距离小于浏览器可视高度
  21:         clearInterval(this.it);//清除定时器
  22:         return func();
  23:     }
  24: }
  25:  
  26: Lazyload.prototype.getY=function(){//目标节点距页面顶部高度
  27:     var obj=this.obj;
  28:     tp = obj.offsetTop;
  29:     if (obj.offsetParent) while (obj = obj.offsetParent) tp += obj.offsetTop;
  30:     return tp;
  31: }

关于代码的一些解释都在注释里了。如何使用呢?

使用这个方法要通过new来新建类对象的方法。参数func即是要触发的函数,obj即是页面上某个节点对象,即当此obj节点进入可视区域时(浏览器滚动到此处)即触发func函数。比如,你要实现当浏览器滚动到页面上id为“test”的节点(b)时触发弹出窗口alert(‘yes’),可以这么做

   1: function a(){alert('yes');}//要出发的函数
   2: var b=document.getElementById('tests');//获取页面节点
   3: new Lazyload(a,b);//使用new关键字建立对象执行

以上就是我自己的lazyload的全部代码与实现方式了。当然,我相信它还有改进之处。

补充一些其他的东西:

我的代码中定时检测的时间设定是2s,也就是说每两秒去比较一次。如果你浏览器拖动太快,目标节点被很快的一闪而过,很可能此时就刚好没有执行checkScroll函数,所以也就不会触发动作了。你可以将时间改为更小的值(在第6行),如500ms,可以避免大多数的快速拖动造成的问题。当然,我觉得其实没必要,如果某人很快的拖动滚动条,说明他要浏览的东西在页面底部,那么其实是没必要加载他快速拖动过的节点的,所以2s我觉得是一个很合理的值。

另外一个问题是我的代码是只触发出现在可视区域中的节点动作,如果你想要实现在当前浏览的页面以上部分的节点全部要加载,那么可以将代码的第20行去掉Math.abs即可。如果要实现在滚动到距目标节点一定高度时就开始触发函数,那么可将20行的seeY改为seeY+200(200即为设定的距离高度)。

关于lazyload的一个具体的实现,就还拿图片的延迟加载来说吧。你可以将图片的地址都改成一个默认的小图片(这个可以在后台用php直接修改输出,也可以用js实现),将正真的图片地址存到图片的alt属性中(也可以指定一个自定义的属性),然后对每个图片绑定new lazyload,要触发的动作函数就是将alt中的值赋给src即可。这样,就实现了图片的lazyload(你就可以消灭jQuery,消灭jQuery的lazyload插件了,也就消灭了那100来K的JS文件)。如果再结合ajax技术,那么也就可以实现如我博客一样的模块延迟加载了。捕获

本文标签: , , , ,

分享

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

这篇文章已经有 98 条评论

Comments (98) Trackbacks (0)
You can leave a response or Trackback this entry .
  1. zwwooooo -#21

    hello,我又来请教了:上次你给我的编辑器js代码为何不能压缩?一压缩就提示“SIMPALED”未定义,而且其他同文件的js也出错(失效)。

    • QiQiBoY --#1

      @zwwooooo
      因为压缩对于代码的格式有要求,有些行尾的分号不能省,所以你最好将每一行正常结束掉的代码都加上分号。我的代码中有些行可能省略了分号。。你加上就可以压缩了。。

    • zwwooooo --#2

      @QiQiBoY
      难怪鸟……自己实在太懒鸟

    • zwwooooo --#3

      @QiQiBoY
      刚才认真检查加了2、3个漏了的分号,还是不行,即使单独压缩这段代码也不行,算了,不折腾了。

    • QiQiBoY --#4

      @zwwooooo
      单独压缩我的代码行不行。。。要是单独压缩还是有错,你把代码发给我,我帮你看看吧。。

    • zwwooooo --#5

      @QiQiBoY
      已发邮件,麻烦你看看

  2. 宿迁学院论坛 -#22

    js代码也能这样的延时?
    太强大了 收藏
    下次 我也加上去~

  3. 人好哇! -#23

    我觉得这种反而给用户体验变差了。本来可以一次载入的东西现在滚动下去才看到再LOADING的标记,变相的增加了等待时间呢!
    技术虽然很好,但是还是要考虑考虑用户体验哦!

    • QiQiBoY --#1

      @人好哇!
      因为你没体验过那种服务器超载时网页加载等待的痛苦。。lazyload就是解决页面一次加载太大、按需加载的。。。。至于看到loading图标,你在我这里我一定会看到的,因为我喜欢看loading,这是我的博客。。但是我文中也说了,你可以通过设置offset距离来预先加载。。那样就可以在用户还没滚动到时就开始加载下面的内容了。。

    • 人好哇! --#2

      @QiQiBoY
      呵呵,受教了。不过服务器如果超载的话,的确很痛苦。

  4. A.shun -#24

    嘛,感觉你好像很不喜欢用jQuery
    因为速度么

    • QiQiBoY --#1

      @A.shun
      嗯。。对jQuery不讨厌,但是也说不上喜欢。。。我觉得jQuery有两点让我很不爽,一是需要先加载它这个库,如果没加载,则基于jQuery的代码都不会运行。。如果你JS代码没组织好,甚至会影响你页面其它非jQuery代码的执行。有段时间google不稳定,结果导致我页面的代码全部报废。。。二是有些浪费,jQuery的功能组件如果能按需加载就好了,比如它可以分为UI包、DOM包、事件包等等。。很多人喜欢jQuery的特效,那就只加载UI包就好了。。

    • A.shun --#2

      @QiQiBoY
      原来如此。
      我不用google的链接。。放在了自己的主题目录,稳定点。

      是啊,主题现在用到jq很小一部分功能而已。。

  5. 江流 -#25

    我就不用了 还是一次过刷新吧。。

  6. 小邪 -#26

    对鸟,能不能把下面这段代码也改成纯js的 ~
    那样我就可以脱离jquery的100多K鸟 ~
    <script type="text/javascript">

    jQuery(document).ready(function($){$('.reply').click(function(){var atid='"#'+$(this).parent().attr("id")+'"';var atname=$(this).prevAll().find('cite:first').text();$("#comment").attr("value","<a href="+atid+" rel="+'"nofollow"'+">@"+atname+" </a>, ").focus()});$('.cancel-comment-reply a').click(function(){$("#comment").attr("value",'')})})

    </script>

  7. 阿吴 -#27

    你的博客好多赞的技术

  8. oYoo -#28

    延迟加载,感觉很酷。

  9. 捷易通 -#29

    原来是lazy技术呀!

  10. mcooo -#30

    http://mcooo.com/javascript-image-loading-delay.html
    这里也有个延时加载图片的 JavaScript 代码,不过你这个看起来好像还要简单,关键代码少了很多。。。你这个代码在大多数的浏览器里都可以用吧!

  11. mcooo -#31

    这个可以多处利用吧。。用在多个不同的ID上?

  12. 花花 -#32

    想问一下,你那个new Lazyload(a,b);里面的A函数里的内容是要AJAX来显示数据么?我不想AJAX来显示怎么办

    • QiQiBoY --#1

      @花花
      第一个参数为回调函数,没有限制一定要是ajax方法,任意函数都可以,你想到时触发什么操作,就传递那个函数即可

    • 花花 --#2

      @QiQiBoY
      但是如果我隐藏要显示的文本的话,等于页面在加载的时候还会加载那些东西,只不过不显示,我不想让加载时,页面的负载过大

  13. mac -#33

    new Lazyload(a,b)中的b,不能是数组吗?

  14. 阿紫 -#34

    请问 a 函数可以有参数吗?

  15. sking7 -#35

    setInterval为啥不用监听scroll函数来替代呢

  1. No trackbacks yet.

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: