jQuery滚动加载图片实现原理


Posted in Javascript onDecember 14, 2015

本文主要通过以下几方面来说明懒加载技术的原理,个人前端小菜,有错误请多多指出

一、什么是图片滚动加载?

通俗的讲就是:当访问一个页面的时候,先把img元素或是其他元素的背景图片路径替换成一张大小为1*1px图片的路径(这样就只需请求一次),只有当图片出现在浏览器的可视区域内时,才设置图片正真的路径,让图片显示出来。这就是图片懒加载。

二、为什要使用这个技术?

比如一个页面中有很多图片,如淘宝、京东首页等等,如果一上来就发送这么多请求,页面加载就会很漫长,如果js文件都放在了文档的底部,恰巧页面的头部又依赖这个js文件,那就不好办了。更为要命的是:一上来就发送百八十个请求,服务器可能就吃不消了(又不是只有一两个人在访问这个页面)。

因此优点就很明显了:不仅可以减轻服务器的压力,而且可以让加载好的页面更快地呈现在用户面前(用户体验好)。

三、怎么实现?

关键点如下:

      1、页面中的img元素,如果没有src属性,浏览器就不会发出请求去下载图片(也就没有请求咯,也就提高性能咯),一旦通过javascript设置了图片路径,浏览器才会送请求。有点按需分配的意思,你不想看,就不给你看,你想看了就给你看~

2、如何获取正真的路径,这个简单,现在正真的路径存在元素的“data-url”(这个名字起个自己认识好记的就行)属性里,要用的时候就取出来,再设置;

3、开始比较之前,先了解一些基本的知识,比如说如何获取某个元素的尺寸大小、滚动条滚动距离及偏移位置距离; 

1)屏幕可视窗口大小:对应于图中1、2位置处

原生方法:window.innerHeight 标准浏览器及IE9+ || document.documentElement.clientHeight 标准浏览器及低版本IE标准模式 || document.body.clientHeight 低版本混杂模式

    

jQuery方法: $(window).height()

2)浏览器窗口顶部与文档顶部之间的距离,也就是滚动条滚动的距离:也就是图中3、4处对应的位置;

原生方法:window.pagYoffset——IE9+及标准浏览器 || document.documentElement.scrollTop 兼容ie低版本的标准模式 || document.body.scrollTop 兼容混杂模式;

    

jQuery方法:$(document).scrollTop();

3)获取元素的尺寸:对应于图中5、6位置处;左边jquery方法,右边原生方法

$(o).width() = o.style.width;

$(o).innerWidth() = o.style.width+o.style.padding;

$(o).outerWidth() = o.offsetWidth = o.style.width+o.style.padding+o.style.border;

$(o).outerWidth(true) = o.style.width+o.style.padding+o.style.border+o.style.margin;

注意:要使用原生的style.xxx方法获取属性,这个元素必须已经有内嵌的样式,如<div style="...."></div>;

如果原先是通过外部或内部样式表定义css样式,必须使用o.currentStyle[xxx] ||document.defaultView.getComputedStyle(0)[xxx]来获取样式值

4)获取元素的位置信息:对应与图中7、8位置处

1)返回元素相对于文档document顶部、左边的距离;

jQuery:$(o).offset().top元素距离文档顶的距离,$(o).offset().left元素距离文档左边缘的距离

原生:getoffsetTop(),高程上有具体说明,这边就忽略了;

 

  顺便提一下返回元素相对于第一个以定位的父元素的偏移距离,注意与上面偏移距的区别;

   

  jQuery:position()返回一个对象,$(o).position().left = style.left,$(o).position().top = style.top;

4、知道如何获取元素尺寸、偏移距离后,接下来一个问题就是:如何判断某个元素进入或者即将进入可视窗口区域?下面也通过一张图来说明问题。

jQuery滚动加载图片实现原理

1)外面最大的框为实际页面的大小,中间浅蓝色的框代表父元素的大小,对象1~8代表元素位于页面上的实际位置;以水平方向来做如下说明!

2)对象8左边界相对于页面左边界的偏移距离(offsetLeft)大于父元素右边界相对于页面左边界的距离,此时可判读元素位于父元素之外;

3)对象7左边界跨过了父元素右边界,此时:对象7左边界相对于页面左边界的偏移距离(offsetLeft)小于 父元素右边界相对于页面左边界的距离,因此对象7就进入了父元素可视区;

4)在对象6的位置处,对象5的右边界与页面左边界的距离 大于 父元素左边界与页面左边界的距离;

5)在对象5位置处时,对象5的右边界与页面左边界的距离 小于 父元素左边界与页面左边界的距离;此时,可判断元素处于父元素可视区外;

6)因此水平方向必须买足两个条件,才能说明元素位于父元素的可视区内;同理垂直方向也必须满足两个条件;具体见下文的源码;

四、扩展为jquery插件
使用方法:$("selector").scrollLoad({ 参数在代码中有说明 })

(function($) {
 $.fn.scrollLoading = function(options) {
 var defaults = {
  // 在html标签中存放的属性名称;
  attr: "data-url",
  // 父元素默认为window
  container: window,
  callback: $.noop
 };
 // 不管有没有传入参数,先合并再说;
 var params = $.extend({}, defaults, options || {});
 // 把父元素转为jquery对象;
 var container = $(params.container);
 // 新建一个数组,然后调用each方法,用于存储每个dom对象相关的数据;
 params.cache = [];
 $(this).each(function() {
  // 取出jquery对象中每个dom对象的节点类型,取出每个dom对象上设置的图片路径
  var node = this.nodeName.toLowerCase(), url = $(this).attr(params["attr"]);
  //重组,把每个dom对象上的属性存为一个对象;
  var data = {
  obj: $(this),
  tag: node,
  url: url
  };
  // 把这个对象加到一个数组中;
  params.cache.push(data);
 });

 var callback = function(call) {
  if ($.isFunction(params.callback)) {
  params.callback.call(call);
  }
 };
 
 //每次触发滚动事件时,对每个dom元素与container元素进行位置判断,如果满足条件,就把路径赋予这个dom元素!
 var loading = function() {
  // 获取父元素的高度
  var contHeight = container.outerHeight();
  var contWidth = container.outerWidth();

  // 获取父元素相对于文档页顶部的距离,这边要注意了,分为以下两种情况;
  if (container.get(0) === window) {
  // 第一种情况父元素为window,获取浏览器滚动条已滚动的距离;$(window)没有offset()方法;
  var contop = $(window).scrollTop();
  var conleft = $(window).scrollLeft();
  } else {
  // 第二种情况父元素为非window元素,获取它的滚动条滚动的距离;
  var contop = container.offset().top;
  var conleft = container.offset().left;
  }

  $.each(params.cache, function(i, data) {
  var o = data.obj, tag = data.tag, url = data.url, post, posb, posl, posr;
  if (o) {
   //对象顶部与文档顶部之间的距离,如果它小于父元素底部与文档顶部的距离,则说明垂直方向上已经进入可视区域了;
   post = o.offset().top - (contop + contHeight);
   //对象底部与文档顶部之间的距离,如果它大于父元素顶部与文档顶部的距离,则说明垂直方向上已经进入可视区域了;
   posb = o.offset().top + o.height() - contop;

   // 水平方向上同理;
   posl = o.offset().left - (conleft + contWidth);
   posr = o.offset().left + o.width() - conleft;

   // 只有当这个对象是可视的,并且这四个条件都满足时,才能给这个对象赋予图片路径;
   if ( o.is(':visible') && (post < 0 && posb > 0) && (posl < 0 && posr > 0) ) {
   if (url) {
    //在浏览器窗口内
    if (tag === "img") {
    //设置图片src
    callback(o.attr("src", url));
    } else {
    // 设置除img之外元素的背景url
    callback(o.css("background-image", "url("+ url +")"));
    }
   } else {
    // 无地址,直接触发回调
    callback(o);
   }
   // 给对象设置完图片路径之后,把params.cache中的对象给清除掉;对象再进入可视区,就不再进行重复设置了;
   data.obj = null;
   }
  }
  });
 };
 //加载完毕即执行
 loading();
 //滚动执行
 container.bind("scroll", loading);
 };
})(jQuery);

本文已被整理到了《jquery图片加载方法汇总》 ,欢迎大家学习阅读。

以上就是滚动加载图片实现原理的详细内容介绍,希望对大家的学习有所帮助。

Javascript 相关文章推荐
JavaScript使用prototype定义对象类型(转)[
Dec 22 Javascript
一个简单的JavaScript数据缓存系统实现代码
Oct 24 Javascript
Javascript公共脚本库系列(一): 弹出层脚本
Feb 24 Javascript
Javascript 面向对象编程(一) 封装
Aug 28 Javascript
获取非最后一列td值并将title设为该值的方法
Oct 30 Javascript
JavaScript子类用Object.getPrototypeOf去调用父类方法解析
Dec 05 Javascript
jQuery中的read和JavaScript中的onload函数的区别
Aug 27 Javascript
JavaScript中连接操作Oracle数据库实例
Apr 02 Javascript
js实现全国省份城市级联下拉菜单效果代码
Sep 07 Javascript
JavaScript Math.round() 方法
Dec 18 Javascript
js实现仿qq消息的弹出窗效果
Jan 06 Javascript
详解Vue.js中.native修饰符
Apr 24 Javascript
jQuery点击按钮弹出遮罩层且内容居中特效
Dec 14 #Javascript
jquery实现倒计时效果
Dec 14 #Javascript
JavaScript 七大技巧(一)
Dec 13 #Javascript
JavaScript 七大技巧(二)
Dec 13 #Javascript
js自定义回调函数
Dec 13 #Javascript
由浅入深讲解Javascript继承机制与simple-inheritance源码分析
Dec 13 #Javascript
分享Javascript实用方法二
Dec 13 #Javascript
You might like
在windows iis5下安装php4.0+mysql之我见
2006/10/09 PHP
destoon在360浏览器下出现用户被强行注销的解决方法
2014/06/26 PHP
PHP+MySQL插入操作实例
2015/01/21 PHP
JQuery困惑—包装集 DOM节点
2009/10/16 Javascript
自写简单JS判断是否已经弹出页面
2010/10/20 Javascript
Tab页界面 用jQuery及Ajax技术实现(php后台)
2011/10/12 Javascript
理解Javascript闭包
2013/11/01 Javascript
Jquery中children与find之间的区别详细解析
2013/11/29 Javascript
如何将php数组或者对象传递给javascript
2014/03/20 Javascript
JQuery动画animate的stop方法使用详解
2014/05/09 Javascript
省市区三级联动下拉框菜单javascript版
2015/08/11 Javascript
jQuery实现固定在网页顶部的菜单效果代码
2015/09/02 Javascript
跟我学习javascript的循环
2015/11/18 Javascript
jQuery文件上传控件 Uploadify 详解
2016/06/20 Javascript
Bootstrap模态框(modal)垂直居中的实例代码
2016/08/18 Javascript
javascript中数组(Array)对象和字符串(String)对象的常用方法总结
2016/12/15 Javascript
解决axios发送post请求返回400状态码的问题
2018/08/11 Javascript
Angular使用Restful的增删改
2018/12/28 Javascript
JQuery复选框全选效果如何实现
2020/05/08 jQuery
总结Python编程中三条常用的技巧
2015/05/11 Python
Python开发微信公众平台的方法详解【基于weixin-knife】
2017/07/08 Python
使用python 计算百分位数实现数据分箱代码
2020/03/03 Python
python实现简单井字棋小游戏
2020/03/05 Python
PyQt5实现仿QQ贴边隐藏功能的实例代码
2020/05/24 Python
python Timer 类使用介绍
2020/12/28 Python
详解解决jupyter不能使用pytorch的问题
2021/02/18 Python
html5拍照功能实现代码(htm5上传文件)
2013/12/11 HTML / CSS
美国知名平价彩妆品牌:e.l.f. Cosmetics
2017/11/20 全球购物
食堂采购员岗位职责
2014/03/17 职场文书
公司经理聘任书
2014/03/29 职场文书
纠纷协议书
2014/04/16 职场文书
文明演讲稿范文
2014/05/12 职场文书
单位作风建设自查报告
2014/10/23 职场文书
2014年店长工作总结
2014/11/17 职场文书
2014年劳动部工作总结
2014/12/11 职场文书
Django中的JWT身份验证的实现
2021/05/07 Python