瀑布流懶加載


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寫法


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM