使用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 相关文章推荐
转一个日期输入控件,支持FF
Apr 27 Javascript
jqPlot 图表中文API使用文档及源码和在线示例
Feb 07 Javascript
自己写的兼容ie和ff的在线文本编辑器类似ewebeditor
Dec 12 Javascript
3种Jquery限制文本框只能输入数字字母的方法
Dec 03 Javascript
JS获取地址栏参数的两种方法(简单实用)
Jun 14 Javascript
详解Angular.js指令中scope类型的几种特殊情况
Feb 21 Javascript
canvas绘制多边形
Feb 24 Javascript
利用nvm管理多个版本的node.js与npm详解
Nov 02 Javascript
浅谈vue自定义全局组件并通过全局方法 Vue.use() 使用该组件
Dec 07 Javascript
ES6 fetch函数与后台交互实现
Nov 14 Javascript
Vue+Java 通过websocket实现服务器与客户端双向通信操作
Sep 22 Javascript
vue动态绑定style样式
Apr 20 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
PHP面向对象的使用教程 简单数据库连接
2006/11/25 PHP
从零开始学YII2框架(五)快速生成代码工具 Gii 的使用
2014/08/20 PHP
php命令行用法入门实例教程
2014/10/27 PHP
php中实现进程锁与多进程的方法
2016/09/18 PHP
PHP实现的AES双向加密解密功能示例【128位】
2018/09/03 PHP
JQuery对checkbox操作 (循环获取)
2011/05/20 Javascript
jQuery操作checkbox选择(list/table)
2013/04/07 Javascript
js传中文参数controller里获取参数乱码问题解决方法
2014/01/03 Javascript
window.location不跳转的问题解决方法
2014/04/17 Javascript
javascript+ajax实现产品页面加载信息
2015/07/09 Javascript
javascript 中的事件委托详解
2016/10/25 Javascript
Node.js制作简单聊天室
2017/01/12 Javascript
vuejs绑定class和style样式
2017/04/11 Javascript
react-native DatePicker日期选择组件的实现代码
2017/09/12 Javascript
vue实现todolist功能、todolist组件拆分及todolist的删除功能
2019/04/11 Javascript
layui layer select 选择被遮挡的解决方法
2019/09/21 Javascript
JS实现贪吃蛇游戏
2019/11/15 Javascript
Vue 路由间跳转和新开窗口的方式(query、params)
2019/12/25 Javascript
jQuery实现鼠标拖动图片功能
2021/03/04 jQuery
[46:44]DOTA2-DPC中国联赛 正赛 Ehome vs PSG.LGD BO3 第二场 3月7日
2021/03/11 DOTA
python使用循环实现批量创建文件夹示例
2014/03/25 Python
Python生成验证码实例
2014/08/21 Python
python 读取excel文件生成sql文件实例详解
2017/05/12 Python
Python拼接字符串的7种方法总结
2018/11/01 Python
python实现的config文件读写功能示例
2019/09/24 Python
PyCharm导入python项目并配置虚拟环境的教程详解
2019/10/13 Python
pandas统计重复值次数的方法实现
2021/02/20 Python
pandas apply使用多列计算生成新的列实现示例
2021/02/24 Python
如何开发一款堪比APP的微信小程序(腾讯内部团队分享)
2016/12/22 HTML / CSS
拉飞逸官网:Lafayette 148 New York
2020/07/15 全球购物
威盛公司软件C++工程师笔试题面试题
2012/07/16 面试题
红色经典观后感
2015/06/18 职场文书
2016年6月份红领巾广播稿
2015/12/21 职场文书
Django模型层实现多表关系创建和多表操作
2021/07/21 Python
python如何将mat文件转为png
2022/07/15 Python
Python 操作pdf pdfplumber读取PDF写入Exce
2022/08/14 Python