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 相关文章推荐
JQuery的html(data)方法与&amp;lt;script&amp;gt;脚本块的解决方法
Mar 09 Javascript
远离JS灾难css灾难之 js私有函数和css选择器作为容器
Dec 11 Javascript
获取内联和链接中的样式(js代码)
Apr 11 Javascript
JQuery控制div外点击隐藏而div内点击不会隐藏的方法
Jan 13 Javascript
JS实现的简洁二级导航菜单雏形效果
Oct 13 Javascript
jquery遍历函数siblings()用法实例
Dec 24 Javascript
论Bootstrap3和Foundation5网格系统的异同
May 16 Javascript
jquery解析XML及获取XML节点名称的实现代码
May 18 Javascript
ES6中的箭头函数实例详解
Apr 06 Javascript
easyui简介_动力节点Java学院整理
Jul 14 Javascript
Vue ElementUI之Form表单验证遇到的问题
Aug 21 Javascript
QML实现圆环颜色选择器
Sep 25 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
php 取得瑞年与平年的天数的代码
2009/08/10 PHP
深入HTTP响应状态码速查表的详解
2013/06/07 PHP
JoshChen_php新手进阶高手不可或缺的规范介绍
2013/08/16 PHP
从零开始学YII2框架(三)扩展插件yii2-gird
2014/08/20 PHP
PHP实现验证码校验功能
2017/11/16 PHP
ThinkPHP整合datatables实现服务端分页的示例代码
2018/02/10 PHP
PHP测试框架PHPUnit组织测试操作示例
2018/05/28 PHP
javascript之对系统的toFixed()方法的修正
2007/05/08 Javascript
学习ExtJS table布局
2009/10/08 Javascript
javascript 弹出窗口中是否显示地址栏的实现代码
2011/04/14 Javascript
浏览器解析js生成的html出现样式问题的解决方法
2012/04/16 Javascript
重写javascript中window.confirm的行为
2012/10/21 Javascript
鼠标焦点离开文本框时验证的js代码
2013/07/19 Javascript
28个常用JavaScript方法集锦
2015/01/14 Javascript
jQuery鼠标经过方形图片切换成圆边效果代码分享
2015/08/20 Javascript
jQuery制作圣诞主题页面 更像是爱情影集
2016/08/10 Javascript
jquery根据td给相同tr下其他td赋值的实现方法
2016/10/05 Javascript
Vue响应式原理详解
2017/04/18 Javascript
基于Vue 2.0的模块化前端 UI 组件库小结
2017/12/21 Javascript
基于vue.js中关于下拉框的值默认及绑定问题
2018/08/22 Javascript
Vue 菜单栏点击切换单个class(高亮)的方法
2018/08/22 Javascript
vue自动路由-单页面项目(非build时构建)
2019/04/30 Javascript
vue.js实现简单的计算器功能
2020/02/22 Javascript
Django中更新多个对象数据与删除对象的方法
2015/07/17 Python
Python(TensorFlow框架)实现手写数字识别系统的方法
2018/05/29 Python
Python函数的参数常见分类与用法实例详解
2019/03/30 Python
利用python-docx模块写批量生日邀请函
2019/08/26 Python
Python进程池Pool应用实例分析
2019/11/27 Python
python定间隔取点(np.linspace)的实现
2019/11/27 Python
python GUI库图形界面开发之PyQt5简单绘图板实例与代码分析
2020/03/08 Python
解决pycharm中的run和debug失效无法点击运行
2020/06/09 Python
英国门把手公司:Door Handle Company
2019/05/12 全球购物
见习期自我鉴定
2013/11/07 职场文书
通信工程专业求职信
2014/06/04 职场文书
2015年财务人员工作总结
2015/04/10 职场文书
教你部署vue项目到docker
2022/04/05 Vue.js