HTML/CSS
<style> body{ margin:0; padding:0; list-style:none; } #container{ position:relative; } #container .box{ float:left; padding:5px; } #container .box-img{ padding:5px; border-radius:5px; box-shadow:0 0 5px #ccc; border:1px solid #B8B8B8; } #container img{ width:230px; height:auto; } </style> <body> <div id='container'> <div class='box'> <div class='box-img'> <img src="images/594A.png" /> </div> </div> <div class='box'> <div class='box-img'> <img src="images/5.jpg"> </div> </div> <div class='box'> <div class='box-img'> <img src="images/mn3.jpg"> </div> </div> <div class='box'> <div class='box-img'> <img src="images/ym.jpg"> </div> </div> <div class='box'> <div class='box-img'> <img src="images/600A.png"> </div> </div> <div class='box'> <div class='box-img'> <img src="images/605A.png"> </div> </div> </div> </body>
效果
1.0-->首先使用JS計算出每一行顯示多少列的圖片
列數 = 內容可視區的寬度(瀏覽器寬度) / 圖片容器的寬度
讓圖片居中
var oParent = document.getElementById('container');//1.獲取父元素 window.addEventListener('load',()=>{ imgLocation('box'); }); const imgLocation = (child) =>{ const oContent = getChild(child); const imgWidth = oContent[0].offsetWidth;//圖片寬度 const num = ~~(document.documentElement.clientWidth / imgWidth);//每一行圖片顯示的列數 oParent.style.cssText = 'width:'+imgWidth*num+'px; margin:0 auto';//設置container寬度,並在瀏覽器中居中顯示 } const getChild = (child) =>{ const childArr = []; const tagsAll = oParent.getElementsByTagName('*');//獲取所有子元素 [].map.call(tagsAll,(current)=>{ if(current.className == child){ childArr.push(current); } });
提示:const是ES6的聲明關鍵字,類似於ES5中的var聲明一樣.
const imgLocation = (child) =>{}這是ES6聲明方法的語法; ES5原來的語法 var imgLocation = function(child){}
const num = ~~(document.documentElement.clientWidth / imgWidth)取整; 這里也可以這樣寫,使用Math.floor方法
const num = Math.floor(document.documentElement.clientWidth / imgWidth);
~~與Math.floor區別
~~只是單純的去除小數,不管正負都不會改變整數部分
2.0-->根據每一列最小的高度
-->把圖片放在每一列高度最小高度圖片的下方
2.1-->計算每一列最小高度
前5個元素不需要操作
var oParent = document.getElementById('container');//1.獲取父元素 window.addEventListener('load',()=>{ imgLocation('box'); }); const imgLocation = (child) =>{ const oContent = getChild(child);//獲取所有子元素 const imgWidth = oContent[0].offsetWidth;//圖片寬度 const num = ~~(document.documentElement.clientWidth / imgWidth);//每一行圖片顯示的列數 oParent.style.cssText = 'width:'+imgWidth*num+'px; margin:0 auto';//設置container寬度,並在瀏覽器中居中顯示 const heightArr = []; [].map.call(oContent,(current,index) =>{ if(index < 5){ heightArr.push(current.offsetHeight); }else{ const minHeight = Math.min(...heightArr); const minIndex = getMinIndex(heightArr).index;//最小序列號 current.style.position = 'absolute'; current.style.top = minHeight + 'px'; current.style.left = oContent[minIndex].offsetLeft+'px'; heightArr[minIndex] = heightArr[minIndex] + current.offsetHeight; } }); } const getChild = (child) =>{ const childArr = []; const tagsAll = oParent.getElementsByTagName('*');//獲取所有子元素 [].map.call(tagsAll,(current)=>{ if(current.className == child){ childArr.push(current); } }); function getMinIndex(arr){ return arr.reduce((a,b,index,arr) =>{ if(b <= a.val){ a.val = b; a.index = index; } return a; },{val:arr[0],index:0}); }
先是拿到第一行集合中的每一個圖片高度,創建一個空的數組heightArr用於存儲第一行所有圖片的高度
[].map.call()也可以寫成Array.prototype.map.call();在這里就直接簡寫[]代表空數組
[].map.call(oContent,(current,index) =>{})------>oContent是獲取所有子元素的集合不是數組,所以這里需要call方法,call方法我是這樣理解的,當前對象(oContent)指代這個空數組
傳入兩個參數(current,index) =>{}這里需要做個判斷if,因為前面5列是不需要操作,但是需要一個初始值current.offsetHeight表示當前(第一行的5張圖片)元素的高度.index<5是做這個
操作current.offsetHeight,因為5張圖片的下標是0-4,所以只做初始化,而需要操作的是第6張圖片
const minHeight=Math.min(...heightArr)表示拿到當前5張圖片中最小的高度的圖片 ...擴展運算符屬於ES6方法 var arr = [1,2,3]; console.log(...arr);結果為1,2,3
getIndex方法 返回的是arr.reduce(a,b,index,arr)=>{...},{val:arr[0],index:0});的對象
arr.reduce(a,b,index,arr)說明這4個參數表示什么?
a表示數組中第一個值,
b表示數組中第二個值,(這個是用來和第一個值做比較的)
index表示數組中的下標
arr表示當前數組(在這里表示的是heightArr這個數組)
{val:arr[0],index:0}表示初始化對象類似--->var obj = {val:heightArr[0],index:0} obj對象有2個屬性val和index,val的值是heightArr[0],index下標為0.這是不懂可以去看下js對象寫法
if(b <=a.val){ a.val =b; a.index=index} 這里表示取最小值和最小值的下標.
a.val和a.index表示調用這個對象的屬性---> var obj = {val:'1',index:'0'},獲取對象里的值:對象.屬性--->console.log(obj.val);結果為1
current.style.position,
current.style.top,
current.style.left
這三個操作表示給第6張圖片定位在上一行中高度最小值圖片的下方.
heightArr[minIndex] = heightArr[minIndex] + current.offsetHeight;最后操作是更新現在圖片的高度(原來圖片的高度+定位圖片的高度=現在圖片的高度)
提示:current,index是map方法里的參數 map有3個current表示當前值,index是下標 arr表示數組
3.0-->判斷滾動條滾動到底部加載圖片
滾動高度+可視區高度 > 加載最后一張圖片距離瀏覽器頂部高度
window.addEventListener('load',() => {//事件監聽 imgLocation('box'); const imgData = [{'src':'596A.png'},{'src':'607A.png'},{'src':'608A.png'},{'src':'609A.png'},{'src':'611A.png'}, {'src':'614A.png'},{'src':'616A.png'},{'src':'617A.png'},{'src':'618A.png'},{'src':'619A.png'},{'src':'620A.png'},{'src':'622A.png'},{'src':'637A.png'},{'src':'639A.png'},{'src':'636A.png'}]; this.addEventListener('scroll',()=>{ if(checkLoading('box')){ imgData.map((current)=>{ console.log(current); const oDiv = document.createElement('div'); oDiv.className = 'box'; oParent.appendChild(oDiv); const oImg = document.createElement('div') oImg.className = 'box-img'; oDiv.appendChild(oImg); const img = new Image(); img.src = 'images/'+current.src+''; oImg.appendChild(img); }); imgLocation('box'); } }); }); const checkLoading = (child) =>{ const oContent = getChilds(child); const lastTop = oContent[oContent.length-1].offsetTop;//最后一個圖片距離瀏覽器的高度 const scrollTop = document.documentElement.scrollTop || document.body.scrollTop;//滾動條高度 const pageHeight = document.documentElement.clientHeight || document.body.clientHeight;//可視區高度 if(scrollTop+pageHeight > lastTop){ return true; } }
checkLoading方法主要操作滾動條滾動到是什么位置需要加載圖片
滾動高度+可視區高度 >最后一張圖片距離到瀏覽器頂部距離
if(scrollTop+pageHeight > lastTop)返回一個true
在監聽器里面操作滾動事件,addEventListener('srcoll',()=>{})動態添加div節點,最后更新所有父元素下box節點imgLocation('box');
完整代碼:
<!DOCTYPE html> <html> <head> <title>瀑布流懶加載</title> <meta charset="utf-8"> </head> <style> body{ margin:0; padding:0; list-style:none; } #container{ position:relative; } #container .box{ float:left; padding:5px; } #container .box-img{ padding:5px; border-radius:5px; box-shadow:0 0 5px #ccc; border:1px solid #B8B8B8; } #container img{ width:230px; height:auto; } </style> <body> <div id='container'> <div class='box'> <div class='box-img'> <img src="images/594A.png" /> </div> </div> <div class='box'> <div class='box-img'> <img src="images/5.jpg"> </div> </div> <div class='box'> <div class='box-img'> <img src="images/mn3.jpg"> </div> </div> <div class='box'> <div class='box-img'> <img src="images/ym.jpg"> </div> </div> <div class='box'> <div class='box-img'> <img src="images/600A.png"> </div> </div> <div class='box'> <div class='box-img'> <img src="images/605A.png"> </div> </div> <div class='box'> <div class='box-img'> <img src="images/595A.png"> </div> </div> <div class='box'> <div class='box-img'> <img src="images/599A.png"> </div> </div> </div> <script> /* 1.0-->實現圖片的列數和瀏覽器寬度關聯 內容顯示區寬度/圖片容器的寬度 = 列數 1.1-->圖片居中 設置margin 2.0-->根據每一列最小的高度 -->把圖片放在每一列高度最小高度圖片的下方 2.1-->計算每一列最小高度 前5個元素不需要操作 3.0-->判斷滾動條滾動到底部加載圖片 滾動高度+可視區高度 > 加載最后一張圖片距離瀏覽器頂部高度 */ var oParent = document.getElementById('container');//父元素 window.addEventListener('load',() => {//事件監聽 imgLocation('box'); const imgData = [{'src':'596A.png'},{'src':'607A.png'},{'src':'608A.png'},{'src':'609A.png'},{'src':'611A.png'}, {'src':'614A.png'},{'src':'616A.png'},{'src':'617A.png'},{'src':'618A.png'},{'src':'619A.png'},{'src':'620A.png'},{'src':'622A.png'},{'src':'637A.png'},{'src':'639A.png'},{'src':'636A.png'}]; this.addEventListener('scroll',()=>{ if(checkLoading('box')){ imgData.map((current)=>{ console.log(current); const oDiv = document.createElement('div'); oDiv.className = 'box'; oParent.appendChild(oDiv); const oImg = document.createElement('div') oImg.className = 'box-img'; oDiv.appendChild(oImg); const img = new Image(); img.src = 'images/'+current.src+''; oImg.appendChild(img); }); imgLocation('box'); } }); }); const checkLoading = (child) =>{ const oContent = getChilds(child); const lastTop = oContent[oContent.length-1].offsetTop;//最后一個圖片距離瀏覽器的高度 const scrollTop = document.documentElement.scrollTop || document.body.scrollTop;//滾動條高度 const pageHeight = document.documentElement.clientHeight || document.body.clientHeight;//可視區高度 if(scrollTop+pageHeight > lastTop){ return true; } } // function imgLocation(){}ES5寫法 ()=>{}等於function() const imgLocation = (child) => {//把父元素所有符合條件的子元素取出來 const oContent = getChilds(child); const imgWidth = oContent[0].offsetWidth;//圖片寬度 //const num = Math.floor(document.documentElement.clientWidth / imgWidth) //列數,這里結果有小數,取整Math.floor()向下取整 const num = ~~(document.documentElement.clientWidth / imgWidth);//第二個取整方法使用~~ oParent.style.cssText = 'width:' + imgWidth*num + 'px; margin: 0 auto'; //使用cssText設置父元素樣式 //計算圖片高度 const heightArr = []; [].map.call(oContent,(current,index) =>{ if(index < 5){ heightArr.push(current.offsetHeight); }else{ // const minHeight = getMin(heightArr); //const minHeight = Math.min.apply(Math,heightArr);//使用Math.min()方法獲取最小值 //獲取最小高度 const minHeight = Math.min(...heightArr);//擴展符... //得到最小高度序列號 // const minIndex = getMinIndex(minHeight,heightArr); const minIndex = getMinIndex(heightArr).index;//最小序列號 current.style.position = 'absolute'; current.style.top = minHeight + 'px'; current.style.left = oContent[minIndex].offsetLeft +'px'; heightArr[minIndex] = heightArr[minIndex] + current.offsetHeight;//更新最小高度 = 已求出最小高度+當前最小高度 // console.log(minIndex); } }); // console.log(num); } const getChilds = (child) => {//3.封裝父元素下所有的子元素方法 const childArr = []; const tagsAll = oParent.getElementsByTagName('*');//獲取所有子元素 [].map.call(tagsAll,(current) =>{//因為tagsAll是html集合不能直接使用,必須使用call方法傳一個參數tagsAll,當前對象指代[](空數組) if(current.className == child){ childArr.push(current); } }); return childArr; // console.log(tagsAll); } /* function getMin(arr){//冒泡排序獲取最小參數 var arrLength = arr.length; for(var i =0,ret = arr[0]; i <arrLength; i++){ ret = Math.min(ret,arr[i]); } return ret; }*/ /*function getMinIndex(minHeight,heightArr){//第一種方法 for( var i in heightArr){ if(heightArr[i] == minHeight){ return i; } } }*/ function getMinIndex(arr){ return arr.reduce((a,b,index,arr) =>{ if(b <= a.val){ a.val = b; a.index = index; } return a; },{val:arr[0],index:0}); } /*var arr = [1,2,3]; var obj = arr.reduce((a,b,index,arr) =>{//用求和方式獲取當前對象下標 if(b<=a.val){ a.val = b; a.index = index; } return a; },{val:arr[0],index:0});*/ </script> </body> </html>
寫得有些亂,因為既有es5寫法也有es6寫法