使用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引导程序
Oct 26 Javascript
js限制文本框为整数和货币的函数代码
Oct 13 Javascript
使用JavaScript构建JSON格式字符串实现步骤
Mar 22 Javascript
使用js操作css实现js改变背景图片示例
Mar 10 Javascript
JavaScript弹出新窗口并控制窗口移动到指定位置的方法
Apr 06 Javascript
JavaScript学习笔记之创建对象
Mar 25 Javascript
再谈javascript注入 黑客必备!
Sep 14 Javascript
详解Vue学习笔记进阶篇之列表过渡及其他
Jul 17 Javascript
简单介绍react redux的中间件的使用
Apr 06 Javascript
浅谈VUE-CLI脚手架热更新太慢的原因和解决方法
Sep 28 Javascript
javascript实现鼠标点击生成文字特效
Dec 24 Javascript
vue.js this.$router.push获取不到params参数问题
Mar 03 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保留两位小数并且四舍五入及不四舍五入的方法
2013/09/22 PHP
PHP根据IP判断地区名信息的示例代码
2014/03/03 PHP
Laravel模型间关系设置分表的方法示例
2018/04/21 PHP
让whoops帮我们告别ThinkPHP6的异常页面
2020/03/02 PHP
PHP filter_var() 函数, 验证判断EMAIL,URL等
2021/03/09 PHP
javascript基于jQuery的表格悬停变色/恢复,表格点击变色/恢复,点击行选Checkbox
2008/08/05 Javascript
JavaScript格式化数字的函数代码
2010/11/30 Javascript
使用apply方法处理数组的三个技巧[译]
2012/09/20 Javascript
jquery datatable后台封装数据示例代码
2014/08/07 Javascript
jQuery中serializeArray()与serialize()的区别实例分析
2015/12/09 Javascript
jQuery中attr()与prop()函数用法实例详解(附用法区别)
2015/12/29 Javascript
基于JavaScript实现根据手机定位获取当前具体位置(X省X市X县X街道X号)
2015/12/29 Javascript
flag和jq on 的绑定多个对象和方法(必看)
2017/02/27 Javascript
基于nodejs+express4.X实现文件下载的实例代码
2017/07/13 NodeJs
vue3.0 CLI - 2.1 -  component 组件入门教程
2018/09/14 Javascript
微信小程序实现顶部下拉菜单栏
2018/11/04 Javascript
js使用Promise实现简单的Ajax缓存
2018/11/14 Javascript
小程序日历控件使用方法详解
2018/12/29 Javascript
JS中创建自定义类型的常用模式总结【工厂模式,构造函数模式,原型模式,动态原型模式等】
2019/01/19 Javascript
小程序中canvas的drawImage方法参数使用详解
2019/07/04 Javascript
RxJS在TypeScript中的简单使用详解
2020/04/13 Javascript
Python中的CURL PycURL使用例子
2014/06/01 Python
解决Django的request.POST获取不到内容的问题
2018/05/28 Python
解决pycharm工程启动卡住没反应的问题
2019/01/19 Python
利用Python裁切tiff图像且读取tiff,shp文件的实例
2020/03/10 Python
python属于解释型语言么
2020/06/15 Python
python 获取谷歌浏览器保存的密码
2021/01/06 Python
HTML5中的Web Notification桌面右下角通知功能的实现
2018/04/19 HTML / CSS
会计电算化个人求职信范文
2014/01/24 职场文书
信息技术毕业生自荐信范文
2014/03/13 职场文书
感恩教育月活动总结
2014/07/07 职场文书
商务英语专业大学生职业生涯规划书
2014/09/14 职场文书
初中教师个人总结
2015/02/10 职场文书
2015年国庆节慰问信
2015/03/23 职场文书
药店收银员岗位职责
2015/04/07 职场文书
Mongo服务重启异常问题的处理方法
2021/07/01 MongoDB