滚动加载图片(懒加载)实现原理

﹏ヽ暗。殇╰゛Y 2022-05-17 05:35 478阅读 0赞

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

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

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

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

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

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

三、怎么实现?

  关键点如下:

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

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

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

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

原生方法:

window.innerHeight 标准浏览器及IE9+

document.documentElement.clientHeight 标准浏览器及低版本IE标准模式

document.body.clientHeight 低版本混杂模式

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

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

原生方法:

window.pageYOffet 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方法获取属性,这个元素必须已经有内嵌的样式,如

4)获取元素的位置信息:对应图中7.8位置处

返回元素相对于document顶部,左边的距离

jQuery:

$(o).offset().top 元素距离文档顶部的距离

$(o).offset().left 元素距离文档左边缘的距离

原生:getoffsetTop()

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

821583-20151210112210543-1357056837.png

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

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

    3)对象7左边界跨过了父元素右边界,此时:对象7左边界相对于页面左边界的偏移距离(offsetLeft)小于 父元素右边界相对于

      页面左边界的距离,因此对象7就进入了父元素可视区;

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

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

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

waterfall.html

  1. <html>
  2. <head>
  3. <title>瀑布流布局</title>
  4. <meta charset="gb2312"/>
  5. <link type="text/css" rel="stylesheet" href="style2.css"/>
  6. <script src="javascript2.js"></script>
  7. </head>
  8. <body>
  9. <div id="main"><!--放置所有图片的容器,设置id方便js获取元素-->
  10. <div class="box"><!--每张图片用一个box装载-->
  11. <div class="pic"><!--在这里放置图片,并设置图片的样式-->
  12. <img src="images/0.jpg"></img>
  13. </div>
  14. </div>
  15. <div class="box">
  16. <div class="pic">
  17. <img src="images/0.jpg"></img>
  18. </div>
  19. </div>
  20. <div class="box">
  21. <div class="pic">
  22. <img src="images/1.jpg"></img>
  23. </div>
  24. </div>
  25. <div class="box">
  26. <div class="pic">
  27. <img src="images/2.jpg"></img>
  28. </div>
  29. </div>
  30. <div class="box">
  31. <div class="pic">
  32. <img src="images/3.jpg"></img>
  33. </div>
  34. </div>
  35. <div class="box">
  36. <div class="pic">
  37. <img src="images/4.jpg"></img>
  38. </div>
  39. </div>
  40. <div class="box">
  41. <div class="pic">
  42. <img src="images/5.jpg"></img>
  43. </div>
  44. </div>
  45. <div class="box">
  46. <div class="pic">
  47. <img src="images/6.jpg"></img>
  48. </div>
  49. </div>
  50. <div class="box">
  51. <div class="pic">
  52. <img src="images/7.jpg"></img>
  53. </div>
  54. </div>
  55. <div class="box">
  56. <div class="pic">
  57. <img src="images/8.jpg"></img>
  58. </div>
  59. </div>
  60. <div class="box">
  61. <div class="pic">
  62. <img src="images/9.jpg"></img>
  63. </div>
  64. </div>
  65. <div class="box">
  66. <div class="pic">
  67. <img src="images/10.jpg"></img>
  68. </div>
  69. </div>
  70. <div class="box">
  71. <div class="pic">
  72. <img src="images/11.jpg"></img>
  73. </div>
  74. </div>
  75. <div class="box">
  76. <div class="pic">
  77. <img src="images/12.jpg"></img>
  78. </div>
  79. </div>
  80. <div class="box">
  81. <div class="pic">
  82. <img src="images/13.jpg"></img>
  83. </div>
  84. </div>
  85. <div class="box">
  86. <div class="pic">
  87. <img src="images/14.jpg"></img>
  88. </div>
  89. </div>
  90. <div class="box">
  91. <div class="pic">
  92. <img src="images/15.jpg"></img>
  93. </div>
  94. </div>
  95. <div class="box">
  96. <div class="pic">
  97. <img src="images/16.jpg"></img>
  98. </div>
  99. </div>
  100. <div class="box">
  101. <div class="pic">
  102. <img src="images/17.jpg"></img>
  103. </div>
  104. </div>
  105. <div class="box">
  106. <div class="pic">
  107. <img src="images/18.jpg"></img>
  108. </div>
  109. </div>
  110. <div class="box">
  111. <div class="pic">
  112. <img src="images/19.jpg"></img>
  113. </div>
  114. </div>
  115. <div class="box">
  116. <div class="pic">
  117. <img src="images/20.jpg"></img>
  118. </div>
  119. </div>
  120. </div>
  121. </body>
  122. </html>

javascript.js

  1. window.onload=function(){
  2. waterfall("main","box");
  3. var imgs={//用json格式模拟从数据库后台抽取出的图片数组
  4. "data":
  5. [
  6. {"src":"0.jpg"},
  7. {"src":"1.jpg"},
  8. {"src":"2.jpg"},
  9. {"src":"3.jpg"},
  10. {"src":"4.jpg"},
  11. {"src":"5.jpg"},
  12. {"src":"6.jpg"},
  13. {"src":"7.jpg"},
  14. {"src":"8.jpg"},
  15. {"src":"9.jpg"},
  16. {"src":"10.jpg"},
  17. {"src":"11.jpg"},
  18. {"src":"12.jpg"},
  19. {"src":"13.jpg"}
  20. ]
  21. }
  22. window.onscroll=function(){
  23. if(checheScrollSlide){
  24. var oparent=document.getElementById("main");
  25. //将数据块渲染到当前页面的尾部
  26. for(var i=0;i<imgs.data.length;i++){
  27. //创建class=box的div元素
  28. var oBox=document.createElement("div");
  29. oBox.className="box";
  30. oparent.appendChild(oBox);
  31. //创建class=pic的div元素
  32. var oPic=document.createElement("div");
  33. oPic.className="pic";
  34. oBox.appendChild(oPic);
  35. //创建图片img
  36. var oImg=document.createElement("img");
  37. oImg.src="images/"+imgs.data[i].src;
  38. oPic.appendChild(oImg);
  39. }
  40. //将加载的图片进行瀑布流排列
  41. waterfall("main","box");
  42. }
  43. }
  44. }
  45. //瀑布流原理:计算出页面总共有多少列,从第二列起,将图片依次放在总高度最小的那一列下面
  46. function waterfall(parent,box){
  47. //1 获取所有装载图片的box
  48. var oparent=document.getElementById(parent);
  49. var oBoxs=getElementByClass(oparent,box);//传入父元素和类名
  50. //2 获取页面宽度
  51. var docWidth=document.documentElement.clientWidth;
  52. //3 获取box宽度
  53. var boxWidth=oBoxs[0].offsetWidth;
  54. //4 计算出列数
  55. var cols=Math.floor(docWidth/boxWidth);
  56. //5 设置页面宽度、居中显示
  57. oparent.style.cssText="width:"+cols*boxWidth+"px;margin:0px auto;";
  58. //6 瀑布流排列
  59. var hArr=[];//存放每一列的高度
  60. for(var i=0;i<oBoxs.length;i++){
  61. //6.1 设置第一列样式
  62. if(i<cols){
  63. hArr.push(oBoxs[i].offsetHeight); //保存第一列的图片高度
  64. }else{ //6.2 设置从第二列起的样式
  65. //找出高度最小的那一张图片的是第几张:index
  66. var minH=Math.min.apply(null,hArr);
  67. var index=getIndex(hArr,minH);
  68. //将下一张图片用绝对定位设置,排列在高度最小的图片下面,并计算此时的列高
  69. oBoxs[i].style.position="absolute";
  70. oBoxs[i].style.top=minH+"px";
  71. oBoxs[i].style.left=oBoxs[index].offsetLeft+"px";
  72. hArr[index]+=oBoxs[i].offsetHeight;
  73. }
  74. }
  75. }
  76. function getElementByClass(oparent,clsname){
  77. var oElements=oparent.getElementsByTagName("*");//获取oparent下的所有子元素
  78. var oBoxs=[];
  79. for(var i=0;i<oElements.length;i++){
  80. if(oElements[i].className==clsname)
  81. oBoxs.push(oElements[i]);
  82. }
  83. return oBoxs;
  84. }
  85. function getIndex(arr,val){
  86. for(var i=0;i<arr.length;i++)
  87. if(arr[i]==val)
  88. return i;
  89. }
  90. //检测是否具备了滚动加载数据块的条件
  91. function checheScrollSlide(){
  92. var oparent=document.getElementById("main");
  93. var oBoxs=getElementByClass(oparent,"box");
  94. //最后一个Box所在列的高度+最后一个box高度的一半
  95. var lastBoxH=oBoxs[oBoxs.length-1].offsetTop+Math.floor(oBoxs[oBoxs.length-1].offsetHeight);
  96. //滚动条拖动的距离(注意混杂模式document.body.scrollTop和标准模式document.documentElement.scrollTop)
  97. var scrollTop=document.body.scrollTop || document.documentElement.scrollTop;
  98. //浏览器可视窗口的高度(注意混杂模式和标准模式)
  99. var height=document.body.clientHeight || document.documentElement.clientHeight;
  100. return(lastBoxH<scrollTop+height)?true:false;//当滚动条下拉到图片的时候
  101. }

style.css

  1. *{
  2. margin:0px;
  3. padding:0px;
  4. }
  5. #mian{
  6. position:relative;
  7. }
  8. .box{
  9. float:left;
  10. padding:15px 0px 0px 15px;
  11. }
  12. .pic{
  13. padding:10px;
  14. border:1px solid #ccc;
  15. border-radius:5px;
  16. box-shadow:0 0 5px #ccc;
  17. }
  18. .pic img{
  19. width:165px;
  20. height:auto;
  21. }

发表评论

表情:
评论列表 (有 0 条评论,478人围观)

还没有评论,来说两句吧...

相关阅读

    相关 图片原理

    背景 懒加载是前端重要的优化手段,尤其是对图片而言,因为非常耗资源。所以我们来了解一下原理吧~ [github地址在此][github] 准备 img标签

    相关 js实现图片原理

    有时候一个网页会包含很多的图片,例如淘宝京东这些购物网站,商品图片多只之又多,页面图片多,加载的图片就多。服务器压力就会很大。不仅影响渲染速度还会浪费带宽。比如一个1M大小的图

    相关 图片实现

    现在网站页面内容越来越丰富,图片内容也越来越多,而图片过多会导致网页文件过大,从而引发加载缓慢的问题,而图片懒加载就是为解决这一问题而生。 首先我们来讲Jquery的懒加载控