使用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 网页黑白效果实现代码(兼容IE/FF等)
Apr 23 Javascript
Javascript变量函数浅析
Sep 02 Javascript
JavaScript中return用法示例
Nov 29 Javascript
jQuery 判断元素整理汇总
Feb 28 Javascript
javascript编写简易计算器
May 06 Javascript
解决bootstrap下拉菜单点击立即隐藏bug的方法
Jun 13 Javascript
详解express与koa中间件模式对比
Aug 07 Javascript
jquery中有哪些api jQuery主要API
Nov 20 jQuery
JavaScript实现简单的文本逐字打印效果示例
Apr 12 Javascript
微信小程序6位或多位验证码密码输入框功能的实现代码
May 29 Javascript
Vue 组件修改根实例的数据的方法
Apr 02 Javascript
jQuery列表动态增加和删除的实现方法
Nov 05 jQuery
用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
smarty巧妙处理iframe中内容页的代码
2012/03/07 PHP
PHP imagecreatefrombmp 从BMP文件或URL新建一图像
2012/07/16 PHP
javascript showModalDialog 多层模态窗口实现页面提交及刷新的代码
2009/11/28 Javascript
JavaScript 高级篇之闭包、模拟类,继承(五)
2012/04/07 Javascript
如何设置iframe高度自适应在跨域情况下的可用方法
2013/09/06 Javascript
Jquery响应回车键直接提交表单操作代码
2014/07/25 Javascript
深入理解JavaScript系列(29):设计模式之装饰者模式详解
2015/03/03 Javascript
JavaScript中boolean类型之三种情景实例代码
2016/11/21 Javascript
概述如何实现一个简单的浏览器端js模块加载器
2016/12/07 Javascript
angularjs使用directive实现分页组件的示例
2017/02/07 Javascript
jquery.cookie.js的介绍与使用方法
2017/02/09 Javascript
详解Vue 事件驱动和依赖追踪
2017/04/22 Javascript
vue页面使用阿里oss上传功能的实例(一)
2017/08/09 Javascript
基于jQuery解决ios10以上版本缩放问题
2017/11/03 jQuery
Node.js使用Express.Router的方法
2017/11/14 Javascript
jQuery基于Ajax实现读取XML数据功能示例
2018/05/31 jQuery
微信小程序使用wxParse解析html的方法教程
2018/07/06 Javascript
原生JavaScript实现remove()和recover()功能示例
2018/07/24 Javascript
原生JS+HTML5实现的可调节写字板功能示例
2018/08/30 Javascript
微信小程序中的canvas 文字断行和省略号显示功能的处理方法
2018/11/14 Javascript
JavaScript计算正方形面积
2019/11/26 Javascript
JS实现电脑虚拟键盘打字测试
2020/06/24 Javascript
JS实现简易图片自动轮播
2020/10/16 Javascript
JS+JQuery实现无缝连接轮播图
2020/12/30 jQuery
详解Python Matplotlib解决绘图X轴值不按数组排序问题
2019/08/05 Python
python数据分析:关键字提取方式
2020/02/24 Python
python列表删除和多重循环退出原理详解
2020/03/26 Python
Python unittest框架操作实例解析
2020/04/13 Python
开发人员所需要知道的HTML5性能分析面面观
2012/07/05 HTML / CSS
前后端结合实现amazeUI分页效果
2020/08/21 HTML / CSS
Java如何获得ResultSet的总行数
2016/09/03 面试题
班长岗位职责
2013/11/10 职场文书
2015年教师节演讲稿范文
2015/03/19 职场文书
2016春季小学开学寄语
2015/12/03 职场文书
quickjs 封装 JavaScript 沙箱详情
2021/11/02 Javascript
yolov5返回坐标的方法实例
2022/03/17 Python