使用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 相关文章推荐
js精度溢出解决方案
Dec 02 Javascript
超级简单的jquery操作表格方法
Dec 15 Javascript
3kb jQuery代码搞定各种树形选择的实现方法
Jun 10 Javascript
JS数组去掉重复数据只保留一条的实现代码
Aug 11 Javascript
ES6中的箭头函数实例详解
Apr 06 Javascript
js实现数字递增特效【仿支付宝我的财富】
May 05 Javascript
JS实现发送短信验证后按钮倒计时功能(防止刷新倒计时失效)
Jul 07 Javascript
mui 打开新窗口的方式总结及注意事项
Aug 20 Javascript
js生成word中图片处理方法
Jan 06 Javascript
vue移动端使用appClound拉起支付宝支付的实现方法
Nov 21 Javascript
SSM VUE Axios详解
Oct 05 Vue.js
Typescript类型系统FLOW静态检查基本规范
May 25 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
Yii2中如何使用modal弹窗(基本使用)
2016/05/30 PHP
破除网页鼠标右键被禁用的绝招大全
2006/12/27 Javascript
JavaScript的类型简单说明
2010/09/03 Javascript
给文字加上着重号的JS代码
2013/11/12 Javascript
JavaScript中如何通过arguments对象实现对象的重载
2014/05/12 Javascript
深入JavaScript高级程序设计之对象、数组(栈方法,队列方法,重排序方法,迭代方法)
2015/12/01 Javascript
JavaScript知识点总结(十)之this关键字
2016/05/31 Javascript
JavaScript实现刷新不重记的倒计时
2016/08/10 Javascript
通过BootStrap实现轮播图的实际应用
2016/09/26 Javascript
JS常用知识点整理
2017/01/21 Javascript
原生js FileReader对象实现图片上传本地预览效果
2020/03/27 Javascript
Node.js创建HTTP文件服务器的使用示例
2018/05/11 Javascript
使用Vue实现图片上传的三种方式
2018/07/17 Javascript
js中getter和setter用法实例分析
2018/08/14 Javascript
vue-cli 引入jQuery,Bootstrap,popper的方法
2018/09/03 jQuery
vue element-ui之怎么封装一个自己的组件的详解
2019/05/20 Javascript
微信小程序用户授权弹窗 拒绝时引导用户重新授权实现
2019/07/29 Javascript
Python中字符串的修改及传参详解
2016/11/30 Python
tensorflow: 查看 tensor详细数值方法
2018/06/13 Python
python用plt画图时,cmp设置方法
2018/12/13 Python
如何在django里上传csv文件并进行入库处理的方法
2019/01/02 Python
Python配置虚拟环境图文步骤
2019/05/20 Python
Python&amp;&amp;GDAL实现NDVI的计算方式
2020/01/09 Python
Python xlwt模块使用代码实例
2020/06/10 Python
CSS3教程(10):CSS3 HSL声明设置颜色
2009/04/02 HTML / CSS
CSS3中的常用选择器使用示例整理
2016/06/13 HTML / CSS
孕妇内衣和胸罩:Cake Maternity
2018/07/16 全球购物
Nike瑞典官方网站:Nike.com (SE)
2018/11/26 全球购物
学生会竞选演讲稿纪检部
2014/08/25 职场文书
读群众路线的心得体会
2014/09/03 职场文书
单位提档介绍信
2015/10/22 职场文书
初二数学教学反思
2016/02/17 职场文书
golang通过递归遍历生成树状结构的操作
2021/04/28 Golang
Python实现信息轰炸工具(再也不怕说不过别人了)
2021/06/11 Python
聊聊mysql都有哪几种分区方式
2022/04/13 MySQL
MySQL中正则表达式(REGEXP)使用详解
2022/07/07 MySQL