使用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 相关文章推荐
jQuery子属性过滤选择器用法分析
Feb 10 Javascript
JS获取iframe中marginHeight和marginWidth属性的方法
Apr 01 Javascript
实例讲解DataTables固定表格宽度(设置横向滚动条)
Jul 11 Javascript
基于JavaScript实现评论框展开和隐藏功能
Aug 25 Javascript
vue使用vue-i18n实现国际化的实现代码
Apr 08 Javascript
JavaScript设计模式之享元模式实例详解
Jan 17 Javascript
vue项目前端埋点的实现
Mar 06 Javascript
JS实现可用滑块滑动的缓动图代码
Sep 01 Javascript
js中script的上下放置区别,Dom的增删改创建操作实例分析
Dec 16 Javascript
js实现图片上传到服务器和回显
Jan 19 Javascript
vue 调用 RESTful风格接口操作
Aug 11 Javascript
vue中如何自定义右键菜单详解
Dec 08 Vue.js
用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
Banner程序
2006/10/09 PHP
php的日期处理函数及uchome的function_coomon中日期处理函数的研究
2011/01/12 PHP
php Ubb代码编辑器函数代码
2012/07/05 PHP
如何用PHP实现插入排序?
2013/04/10 PHP
PHP XML和数组互相转换详解
2016/10/26 PHP
PHP上传图片、删除图片简单实例
2016/11/12 PHP
Ajax执行顺序流程及回调问题分析
2012/12/10 Javascript
javascript阻止浏览器后退事件防止误操作清空表单
2013/11/22 Javascript
jquery ajax 局部无刷新更新数据的实现案例
2014/02/08 Javascript
浅谈javascript中createElement事件
2014/12/05 Javascript
JavaScript学习笔记之定时器
2015/01/22 Javascript
JavaScript获取元素尺寸和大小操作总结
2015/02/27 Javascript
IE下JS保存图片的简单实例
2016/07/15 Javascript
JS与jQuery实现隔行变色的方法
2016/09/09 Javascript
Jquery Easyui自定义下拉框组件使用详解(21)
2020/12/31 Javascript
jQuery中的siblings()是什么意思(推荐)
2016/12/29 Javascript
基于node打包可执行文件工具_Pkg使用心得分享
2018/01/24 Javascript
实例详解ztree在vue项目中使用并且带有搜索功能
2018/08/24 Javascript
js取0-9随机取4个数不重复的数字代码实例
2019/03/27 Javascript
小程序实现密码输入框
2020/11/16 Javascript
Pycharm学习教程(4) Python解释器的相关配置
2017/05/03 Python
python3使用SMTP发送简单文本邮件
2018/06/19 Python
python根据list重命名文件夹里的所有文件实例
2018/10/25 Python
python3用PIL把图片转换为RGB图片的实例
2019/07/04 Python
pyinstaller参数介绍以及总结详解
2019/07/12 Python
python 在threading中如何处理主进程和子线程的关系
2020/04/25 Python
python温度转换华氏温度实现代码
2020/12/06 Python
Python使用tkinter制作在线翻译软件
2021/02/22 Python
DHC中国官方购物网站:日本通信销售No.1化妆品
2016/08/20 全球购物
澳洲女装时尚在线:Blue Bungalow
2018/05/05 全球购物
Python面试题:Python里面如何生成随机数
2015/03/12 面试题
大学应届生求职简历的自我评价
2013/10/08 职场文书
个人委托书范本
2014/04/02 职场文书
2014企业年终工作总结
2014/12/23 职场文书
MySQL 分组查询的优化方法
2021/05/12 MySQL
Apache SkyWalking 监控 MySQL Server 实战解析
2022/09/23 Servers