使用jquery实现的一个图片延迟加载插件(含图片延迟加载原理)


Posted in Javascript onJune 05, 2014

图片延迟加载也称懒加载,通常应用于图片比较多的网页,如果一个页面图片比较多,且页面高度或宽度有好几屏,页面初次加载时,只显示可视区域的图片,当页面滚动的时候,图片进入了可视区域再进行加载,这样可以显著的提高页面的加载速度,更少的图片并发请求数也可以减轻服务器的压力。如果用户仅仅在首屏停留,还可以节省流量。如果TAB中的图片较多,也同样可以应用于TAB中,当触发TAB时再进行图片的加载。

图片延迟加载的原理比较简单,先将图片的真实地址缓存在一个自定义的属性(lazy-src)中,而src地址使用一个1×1的全透明的占位图片来代替,当然占位图片也可以是其他的图片。

<img src="images/placeholder.png"  lazy-src="images/realimg.jpg" />

因为是使用javascript来加载图片,如果用户禁用了javascript,可以设置一个替代的方案。

<img src="images/placeholder.png"  lazy-src="images/realimg.jpg" alt="" />
<noscript><img src="images/realimg.jpg"  alt="" /></noscript>

页面初次加载时获取图片在页面中的位置并缓存(每次取offset的值会引发页面的reflow),计算出可视区域,当图片的位置出现在可视区域中,将src的值替换成真实的地址,此时图片就开始加载了。

当页面滚动的时候,再判断图片已经缓存的位置值是否出现在可视区域内,进行替换src加载。当所有的图片都加载完之后,将相应的触发事件卸载,避免重复操作引起的内存泄漏。将整个窗口看成是一个大容器,那么也可以在页面中设置一个小容器,在小容器中也同样可以实现图片的延迟加载。

下面是实现的代码,我写成了jQuery插件。

(function( $ ){
$.fn.imglazyload = function( options ){
 var o = $.extend({
    attr  :   'lazy-src', 
    container  :  window, 
    event   :  'scroll',    
    fadeIn      :   false,    
    threshold  :  0, 
    vertical  :  true 
   }, options ),
  event = o.event,
  vertical = o.vertical,
  container = $( o.container ),
  threshold = o.threshold, 
  // 将jQuery对象转换成DOM数组便于操作
  elems = $.makeArray( $(this) ),  
  dataName = 'imglazyload_offset',   
  OFFSET = vertical ? 'top' : 'left',
  SCROLL = vertical ? 'scrollTop' : 'scrollLeft',   
  winSize = vertical ? container.height() : container.width(),
  scrollCoord = container[ SCROLL ](),
  docSize = winSize + scrollCoord;
 // 延迟加载的触发器 
 var trigger = {
  init : function( coord ){
   return coord >= scrollCoord && 
                            coord <= ( docSize + threshold );
  },
  scroll : function( coord ){
   var scrollCoord = container[ SCROLL ]();
   return coord >= scrollCoord && 
                    coord <= ( winSize + scrollCoord + threshold );
  },
  resize : function( coord ){
   var scrollCoord = container[ SCROLL ](),
    winSize = vertical ? 
                            container.height() : 
                            container.width();
   return coord >= scrollCoord &&
                   coord <= ( winSize + scrollCoord + threshold );
  }
 };
 var loader = function( triggerElem, event ){
  var i = 0,
   isCustom = false,
   isTrigger, coord, elem, $elem, lazySrc;
  // 自定义事件只要触发即可,无需再判断
  if( event ){
   if( event !== 'scroll' && event !== 'resize' ){
    isCustom = true;
   }
  }
  else{
   event = 'init';
  }
  for( ; i < elems.length; i++ ){ 
   isTrigger = false;
   elem = elems[i];
   $elem = $( elem );
   lazySrc = $elem.attr( o.attr );
   if( !lazySrc || elem.src === lazySrc ){
    continue;
   }
   // 先从缓存获取offset值,缓存中没有才获取计算值,
   // 将计算值缓存,避免重复获取引起的reflow
   coord = $elem.data( dataName );
   if( coord === undefined ){
    coord = $elem.offset()[ OFFSET ];
    $elem.data( dataName, coord );
   }
   isTrigger = isCustom || trigger[ event ]( coord );   
   if( isTrigger ){
    // 加载图片
    elem.src = lazySrc;
    if( o.fadeIn ){
     $elem.hide().fadeIn();
    }
    // 移除缓存
    $elem.removeData( dataName );
    // 从DOM数组中移除该DOM
    elems.splice( i--, 1 );
   }
  }
  // 所有的图片加载完后卸载触发事件
  if( !elems.length ){
   if( triggerElem ){
    triggerElem.unbind( event, fire );
   }
   else{
    container.unbind( o.event, fire );
   }
   $( window ).unbind( 'resize', fire );
   elems = null;
  }
 };
 var fire = function( e ){
  loader( $(this), e.type );
 };
 // 绑定事件
 container = event === 'scroll' ? container : $( this ); 
 container.bind( event, fire );
 $( window ).bind( 'resize', fire );
 // 初始化
 loader();
 return this;
};
})( jQuery );

调用:

$( 'img' ).imglazyload({
 event : 'scroll',
 attr : 'lazy-src'
});

默认的调用可以省略所有参数。
$( 'img' ).imglazyload();

图片延迟加载的插件API说明:

attr string
存放图片真实地址的属性名,与HTML对应,默认是lazy-src。

container dom & selector
默认的容器为window,可自定义容器。

event stirng
触发图片加载的事件类型,默认为window.onscroll事件

fadeIn boolean
是否使用jQuery的fadeIn效果来显示,默认是false。

threshold number
页面滚动到离图片还有指定距离的时候就进行加载,默认是0。

vertical boolean
是否横向滚动,默认为true(纵向)。

loadScript(增强版的功能) boolean
是否无阻塞加载javascript广告图片,默认为false。

Javascript 相关文章推荐
JavaScript 参考教程
Dec 29 Javascript
jQuery.each()用法分享
Jul 31 Javascript
js时间戳格式化成日期格式的多种方法
Nov 11 Javascript
JS的encodeURI和java的URLDecoder.decode使用介绍
May 08 Javascript
js实现有过渡渐变效果的图片轮播相册(兼容IE,ff)
Jan 19 Javascript
js实现随机抽选效果、随机抽选红色球效果
Jan 13 Javascript
Vue关于数据绑定出错解决办法
May 15 Javascript
浅谈Vuex的状态管理(全家桶)
Nov 04 Javascript
值得收藏的vuejs安装教程
Nov 21 Javascript
使用use注册Vue全局组件和全局指令的方法
Mar 08 Javascript
JS实现快递单打印功能【推荐】
Jun 21 Javascript
使用 Angular RouteReuseStrategy 缓存(路由)组件的实例代码
Nov 01 Javascript
用js的document.write输出的广告无阻塞加载的方法
Jun 05 #Javascript
javascript数组去重方法终极总结
Jun 05 #Javascript
javascript设计模式之解释器模式详解
Jun 05 #Javascript
javascript监听鼠标滚轮事件浅析
Jun 05 #Javascript
详解JavaScript语法对{}处理的坑爹之处
Jun 05 #Javascript
封装了一个支持匿名函数的Javascript事件监听器
Jun 05 #Javascript
用js读、写、删除Cookie代码分享及详细注释说明
Jun 05 #Javascript
You might like
超级好用的一个php上传图片类(随机名,缩略图,加水印)
2010/06/30 PHP
PHPExcel笔记, mpdf导出
2016/05/03 PHP
CI框架整合widget(页面格局)的方法
2016/05/17 PHP
javascript不同页面传值的改进版
2008/09/30 Javascript
鼠标拖动实现DIV排序示例代码
2013/10/14 Javascript
js中confirm实现执行操作前弹出确认框的方法
2014/11/01 Javascript
JS实现的鼠标跟随代码(卡通手型点击效果)
2015/10/26 Javascript
浅谈javascript中onbeforeunload与onunload事件
2015/12/10 Javascript
在JavaScript中对HTML进行反转义详解
2016/05/18 Javascript
全面解析Bootstrap中transition、affix的使用方法
2016/05/30 Javascript
node.JS md5加密中文与php结果不一致的解决方法
2017/05/05 Javascript
JavaScript实现图片拖曳效果
2017/09/08 Javascript
JavaScript程序设计高级算法之动态规划实例分析
2017/11/24 Javascript
基于vue2.0的活动倒计时组件countdown(附源码下载)
2018/10/09 Javascript
Koa代理Http请求的示例代码
2018/10/10 Javascript
Jquery实现获取子元素的方法分析
2019/08/24 jQuery
Vue源码分析之Vue实例初始化详解
2019/08/25 Javascript
node.JS事件机制与events事件模块的使用方法详解
2020/02/06 Javascript
Vue中添加滚动事件设置的方法详解
2020/09/14 Javascript
Python抓取电影天堂电影信息的代码
2016/04/07 Python
详解python tkinter模块安装过程
2020/01/06 Python
Python如何把字典写入到CSV文件的方法示例
2020/08/23 Python
佳能德国网上商店:Canon德国
2017/03/18 全球购物
技能比赛获奖感言
2014/02/14 职场文书
船舶工程技术专业求职信
2014/08/07 职场文书
新员工试用期自我评价
2015/03/10 职场文书
2015年团支书工作总结
2015/04/03 职场文书
检讨书范文大全
2015/05/07 职场文书
2015法院个人工作总结范文
2015/05/25 职场文书
入党积极分子半年考察意见
2015/06/02 职场文书
大国崛起英国观后感
2015/06/02 职场文书
西柏坡观后感
2015/06/08 职场文书
小学班级管理心得体会
2016/01/07 职场文书
Python爬虫之爬取最新更新的小说网站
2021/05/06 Python
实操Python爬取觅知网素材图片示例
2021/11/27 Python
Redis主从复制操作和配置详情
2022/09/23 Redis