js原生瀑布流并实现滚动懒加载(兼容IE8)

最近公司接的新项目,客户要求要把图文列表的形式给写成瀑布流的形式,what?我仔细一想,应该不是很难,毕竟前端是万能的嘛,嘿嘿,之前我也听过瀑布流布局,比如淘宝,天猫等都是用的瀑布流布局,我不知道怎么生成的,于是我就上网找插件,有些插件还不错,不过我想自己写自己的代码,我看别人代码,主要看瀑布流的原理,然后根据原理自己写代码,然后再看慕课网之类的教学网站汲取经验,终于一个瀑布流被我搞出来了,本篇是拿原生js写的瀑布流布局,如果想看jQuery写的瀑布流,请转下一篇

用jQuery实现瀑布流及滚动懒加载(兼容IE8)

当然jquery那一篇我就不说原理了,在这一篇文章中说就好啦!下面我们来看看瀑布流长什么样子
在这里插入图片描述

瀑布流原理:

瀑布流是许多数据块组成的,可以是图片,可以是div,但是它们都有一个特点,就是等宽不等高,正是因为它等宽不等高,所以如果按部就班的排布的话,才会出现很大的缝隙,特别不好看,说白了瀑布流布局就是充分利用图片之间的空隙来合理的布局,使布局看起来好看,符合人眼的审美,下面我们用一幅图来说明
首先
在这里插入图片描述
首先我们肯定要按部就班的先平铺第一行,比如我们平铺了5张图片,然后该平铺第二行了,那这个待插入的图片应该放在哪个位置呢,瀑布流是这个样子的,我们平铺了5张图片,可以看成是5列,每一列都会有高度,它不管排多少张图片,一定会有5列,这个是不变的,我们可以得到每一列的高度,也就是每一列的数据块的高度加起来就ok,得到5个高度的数值,我们算出哪一列高度最小,那么我们就把待插入的图片插入到那一列的正下方,利用绝对定位定位过去,top肯定是高度,left就是第几列乘以数据块宽度就可以了,如下图,待插入图片应该插入到这里
在这里插入图片描述
如果再插入图片,还是找高度最小的那一列,插到那一列的下方,不论有多少图片,永远插入到高度最小的那一列下方,这样就是瀑布流了,形状形似瀑布
下面我们用代码来实现

代码部分:

html部分:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <link rel="stylesheet" href = "./css/waterfall.css">
    <title>原生js瀑布流布局</title>
</head>
<body>
    <div id = "main">
        <div class = "box">
            <div class = "pic">
                <img src = "./img/1.jpg" alt="">
            </div>
        </div>
        <div class = "box">
            <div class = "pic">
                <img src = "./img/2.jpg" alt="">
            </div>
        </div>
        <div class = "box">
            <div class = "pic">
                <img src = "./img/3.jpg" alt="">
            </div>
        </div>
        <div class = "box">
            <div class = "pic">
                <img src = "./img/4.jpg" alt="">
            </div>
        </div>
        <div class = "box">
            <div class = "pic">
                <img src = "./img/5.jpg" alt="">
            </div>
        </div>
        <div class = "box">
            <div class = "pic">
                <img src = "./img/6.jpg" alt="">
            </div>
        </div>
        <div class = "box">
            <div class = "pic">
                <img src = "./img/7.jpg" alt="">
            </div>
        </div>
        <div class = "box">
            <div class = "pic">
                <img src = "./img/8.jpg" alt="">
            </div>
        </div>
        <div class = "box">
            <div class = "pic">
                <img src = "./img/9.jpg" alt="">
            </div>
        </div>
        <div class = "box">
            <div class = "pic">
                <img src = "./img/10.jpg" alt="">
            </div>
        </div>
        <div class = "box">
            <div class = "pic">
                <img src = "./img/11.jpg" alt="">
            </div>
        </div>
        <div class = "box">
            <div class = "pic">
                <img src = "./img/12.jpg" alt="">
            </div>
        </div>
        <div class = "box">
            <div class = "pic">
                <img src = "./img/13.jpg" alt="">
            </div>
        </div>
        <div class = "box">
            <div class = "pic">
                <img src = "./img/14.jpg" alt="">
            </div>
        </div>
        <div class = "box">
            <div class = "pic">
                <img src = "./img/15.jpg" alt="">
            </div>
        </div>
        <div class = "box">
            <div class = "pic">
                <img src = "./img/16.jpg" alt="">
            </div>
        </div>
        <div class = "box">
            <div class = "pic">
                <img src = "./img/17.jpg" alt="">
            </div>
        </div>
        <div class = "box">
            <div class = "pic">
                <img src = "./img/18.jpg" alt="">
            </div>
        </div>
        <div class = "box">
            <div class = "pic">
                <img src = "./img/19.jpg" alt="">
            </div>
        </div>
        <div class = "box">
            <div class = "pic">
                <img src = "./img/20.jpg" alt="">
            </div>
        </div>
    </div>
    <script src = "./js/resource.js"></script>
</body>
</html>

我们用了一个id为main的大div来包含整个瀑布流,要在这个div上加position:relative,所有的图片是相对这个div来绝对定位的,它的宽度我们不会先定义,会用js动态算出来,,我们用了box的div,这个div用来撑起图片之间的宽度,推荐使用padding,不要用margin,因为我们要用到offsetWidth这个属性,它是不会把margin算进去的,然后用了一个pic的div用来放图片,下面就来看看css文件吧

css部分:

*{
    margin:0;
    padding:0;
}
#main{
    position: relative;
}
.box{
    padding:15px 0 0 15px;
    float:left;
}
.pic{
    padding:10px;
    border:1px solid #ccc;
    border-radius: 5px;
    box-shadow: 0 0 5px #ccc;
}
.pic img{
    width:165px;
    height:auto;
}

js部分:

这是重点
首先我们要在window.onload这个函数中来执行瀑布流的函数

window.onload = function(){
	warterfall("main","box");
}

我们定义了一个waterfall的函数,我们在外边定义它,下面直接上代码吧,我会在代码中加注释,各位看注释吧,要不然一句一句写太多了

window.onload = function(){
    //在window加载完毕时调用此函数
    warterfall("main","box");
}
//定义waterfall函数
function warterfall(parent,box){
    //将main下的所有class为box的元素取出来
    var oParent = document.getElementById(parent);
    var oBoxs = getByClass(oParent,box);
    //计算整个页面显示的列数(页面宽/box的宽);
    var oBoxW = oBoxs[0].offsetWidth;
    var cols = Math.floor(document.documentElement.clientWidth/oBoxW);
    //设置mian的宽度
    oParent.style.cssText = 'width:' + oBoxW * cols + 'px;margin:0 auto';
    var hArr = [];
    for(var i = 0; i < oBoxs.length;i++){
        if(i < cols){
            // 将前cols张图片的宽度记录到hArr数组中(第一行的高度)
            hArr.push(oBoxs[i].offsetHeight);
        }else{//从第二行开始就开始找最小的高度了,决定带插入图片该插入到哪里
            // 找到高度最小的值
            var minH = Math.min.apply(null,hArr);
            var index = getMinhIndex(hArr,minH);
            // 设置最小高度的图片的style为绝对定位,并设置top和left
            oBoxs[i].style.position = 'absolute';
            oBoxs[i].style.top = minH + 'px';
            oBoxs[i].style.left = oBoxW * index + 'px';
            hArr[index] += oBoxs[i].offsetHeight;
        }
    }
}
//根据class获取元素
function getByClass(parent,clsName){
    var boxArr = [];//用来存储获取到的所有class为box的元素
    var oElements = parent.getElementsByTagName("*");
    for(var i = 0; i < oElements.length;i++){
        if(oElements[i].className == clsName){
            boxArr.push(oElements[i]);
        }
    }
    return boxArr;
}
//定义函数获取hArr数组中最小值的下标值
function getMinhIndex(arr,val){
    for(var i in arr){
        if(arr[i] == val){
            return i;
        }
    }
}

这样瀑布流的定位就好了,下面我么你来看一下效果图
在这里插入图片描述
下面实现懒加载

懒加载部分:

我们来看一看懒加载的原理,废话不多说,上图
在这里插入图片描述
假设蓝色的框是我们浏览器可视区域,灰色部分是我们瀑布流的那个main的div,现在我们要判断最后一张图片刚露出一半的时候,我们就要滚动加载图片,我们蓝色的数据块就代表最后一张图片,大家看到有一条蓝色的线,和一条黑色的线,蓝色的线代表最后一张图片一半的高度加上最后一张图片距离id为main的div顶部的距离,黑色的线代表滚动条滚动距离加上浏览器可视区域的高度

如果蓝色 < 黑色,那么就可以滚动加载,如果蓝色 > 黑色,那么就不具备滚动加载的条件,所以我们还需要一个函数来判断它能否滚动加载

//定义函数检测是否具备了滚动加载数据块的条件
function checkScrollSlide(){
    var oParent = document.getElementById('main');
    var oBoxs = getByClass(oParent,'box');
    //获取最后一块数据到顶部的距离+ 它自身一半的距离
    var lastBoxH = oBoxs[oBoxs.length - 1].offsetTop + Math.floor(oBoxs[oBoxs.length - 1].offsetHeight/2);
    //获取滚动条滚动距离
    var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
    // 获取window可视化的高度
    var height = document.body.clientHeight || document.documentElement.clientHeight;
    return (lastBoxH < scrollTop + height)?true:false;
}

滚动加载肯定要写在window.onscroll的这个函数里面,不过这个函数也要写在window.onload里卖弄哦!如果可以滚动加载,那么就请求数据,将请求到的数据动态渲染到页面的尾部,这里我就用假数据代替了,模拟一个效果

var dataInt = {
        "data":[
            {
                "src":'./img/1.jpg'
            },
            {
                "src":'./img/3.jpg'
            },
            {
                "src":'./img/5.jpg'
            },
            {
                "src":'./img/8.jpg'
            },
            {
                "src":'./img/12.jpg'
            }
        ]
    }
    //监听window的滚动条事件
    window.onscroll = function(){
        if(checkScrollSlide){
            var oParent = document.getElementById('main');
            //将数据块渲染到页面的尾部
            for(var i = 0;i < dataInt.data.length;i++){
                var oBox = document.createElement("div");
                oBox.className = "box";
                oParent.appendChild(oBox);
                var oPic = document.createElement("div");
                oPic.className = "pic";
                oBox.appendChild(oPic);
                var oImg = document.createElement("img");
                oImg.src = dataInt.data[i].src;
                oPic.appendChild(oImg);
            }
            warterfall("main","box");
        }
    }

好啦现在看下最后的全部js代码吧

完整的js代码:

window.onload = function(){
    //在window加载完毕时调用此函数
    warterfall("main","box");
    var dataInt = {
        "data":[
            {
                "src":'./img/1.jpg'
            },
            {
                "src":'./img/3.jpg'
            },
            {
                "src":'./img/5.jpg'
            },
            {
                "src":'./img/8.jpg'
            },
            {
                "src":'./img/12.jpg'
            }
        ]
    }
    //监听window的滚动条事件
    window.onscroll = function(){
        if(checkScrollSlide){
            var oParent = document.getElementById('main');
            //将数据块渲染到页面的尾部
            for(var i = 0;i < dataInt.data.length;i++){
                var oBox = document.createElement("div");
                oBox.className = "box";
                oParent.appendChild(oBox);
                var oPic = document.createElement("div");
                oPic.className = "pic";
                oBox.appendChild(oPic);
                var oImg = document.createElement("img");
                oImg.src = dataInt.data[i].src;
                oPic.appendChild(oImg);
            }
            warterfall("main","box");
        }
    }
}
//定义waterfall函数
function warterfall(parent,box){
    //将main下的所有class为box的元素取出来
    var oParent = document.getElementById(parent);
    var oBoxs = getByClass(oParent,box);
    //计算整个页面显示的列数(页面宽/box的宽);
    var oBoxW = oBoxs[0].offsetWidth;
    var cols = Math.floor(document.documentElement.clientWidth/oBoxW);
    //设置mian的宽度
    oParent.style.cssText = 'width:' + oBoxW * cols + 'px;margin:0 auto';
    var hArr = [];
    for(var i = 0; i < oBoxs.length;i++){
        if(i < cols){
            // 将前cols张图片的宽度记录到hArr数组中(第一行的高度)
            hArr.push(oBoxs[i].offsetHeight);
        }else{//从第二行开始就开始找最小的高度了,决定带插入图片该插入到哪里
            // 找到高度最小的值
            var minH = Math.min.apply(null,hArr);
            var index = getMinhIndex(hArr,minH);
            // 设置最小高度的图片的style为绝对定位,并设置top和left
            oBoxs[i].style.position = 'absolute';
            oBoxs[i].style.top = minH + 'px';
            oBoxs[i].style.left = oBoxW * index + 'px';
            hArr[index] += oBoxs[i].offsetHeight;
        }
    }
}
//根据class获取元素
function getByClass(parent,clsName){
    var boxArr = [];//用来存储获取到的所有class为box的元素
    var oElements = parent.getElementsByTagName("*");
    for(var i = 0; i < oElements.length;i++){
        if(oElements[i].className == clsName){
            boxArr.push(oElements[i]);
        }
    }
    return boxArr;
}
//定义函数获取hArr数组中最小值的下标值
function getMinhIndex(arr,val){
    for(var i in arr){
        if(arr[i] == val){
            return i;
        }
    }
}
//定义函数检测是否具备了滚动加载数据块的条件
function checkScrollSlide(){
    var oParent = document.getElementById('main');
    var oBoxs = getByClass(oParent,'box');
    //获取最后一块数据到顶部的距离+ 它自身一半的距离
    var lastBoxH = oBoxs[oBoxs.length - 1].offsetTop + Math.floor(oBoxs[oBoxs.length - 1].offsetHeight/2);
    //获取滚动条滚动距离
    var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
    // 获取window可视化的高度
    var height = document.body.clientHeight || document.documentElement.clientHeight;
    return (lastBoxH < scrollTop + height)?true:false;
}

下面看下效果,只能看静态的(5555)

在这里插入图片描述

现在基本上用原生js和滚动懒加载都实现完了,而且兼容IE8哦!如果你想用jQuery简单省事一点,就移步下一篇

用jQuery实现瀑布流及滚动懒加载(兼容IE8)

但是下一篇就不会讲解原理,就直接上代码了哦!!

  • 6
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值