1. 程式人生 > >滾動載入圖片(懶載入)實現原理

滾動載入圖片(懶載入)實現原理

本文主要通過以下幾方面來說明懶載入技術的原理,個人前端小菜,有錯誤請多多指出

一、什麼是圖片滾動載入?

  通俗的講就是:當訪問一個頁面的時候,先把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.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方法獲取屬性,這個元素必須已經有內嵌的樣式,如<div style="...."></div>;

4)獲取元素的位置資訊:對應圖中7.8位置處

返回元素相對於document頂部,左邊的距離

jQuery:

$(o).offset().top          元素距離文件頂部的距離

$(o).offset().left          元素距離文件左邊緣的距離

原生:getoffsetTop()

4、知道如何獲取元素尺寸、偏移距離後,接下來一個問題就是:如何判斷某個元素進入或者即將進入可視視窗區域?下面也通過一張圖來說明問題。

    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. }