瀑布流懒加载

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

猜你喜欢

转载自www.cnblogs.com/Sammy-shan/p/8912672.html