用JavaScript实现瀑布流布局的效果(附源码)

瀑布流,又称瀑布流式布局。是比较流行的一种网站页面布局,视觉表现为参差不齐的多栏布局,随着页面滚动条向下滚动,这种布局还会不断加载数据块并附加至当前尾部。
——摘自百度百科“瀑布流”

制作瀑布流布局,首先需要准备几张图片,将其放置在html页面中。

<head>
    <meta charset="utf-8">
    <title>瀑布流练习</title>
    <link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
    <div id="container">
        <div class="box">
            <div class="box_img">
                <img src="1.jpg" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box_img">
                <img src="2.jpg" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box_img">
                <img src="3.jpg" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box_img">
                <img src="4.jpg" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box_img">
                <img src="5.jpg" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box_img">
                <img src="6.jpg" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box_img">
                <img src="7.jpg" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box_img">
                <img src="8.jpg" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box_img">
                <img src="9.jpg" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box_img">
                <img src="10.jpg" alt="">
            </div>
        </div>
    </div>
</body>

简单设置一下样式并将其样式导入到html中。

/* 去掉边距 */
*{
    margin: 0px;
    padding: 0px;
}
#container{
    position: relative;
}
.box{
    padding: 5px;
    float: left;
}
/* 承载图片的盒子 */
.box_img{
    padding: 5px;
    border: 1px solid #ccc;
    /* 设置阴影 */
    box-shadow: 0 0 5px #ccc; 
    /* 设置圆角 */
    border-radius: 5px;
}
.box_img img{
    width: 150px;
    height: auto;
}

看到一开始的效果如下:
在这里插入图片描述
由于设置了浮动,图片摆放位置会随着窗体变化而变化。
在这里插入图片描述
所以需要将其显示的宽度固定化。同时,根据瀑布流的效果,第二排的第一张照片应该摆在第一排的第四张下面。
在这里插入图片描述
解决的思路:获取第一排所有图片的高度,同时得到最小高度的位置,将第二排第一张图片放置在其下面(后面会说到)。

通过JavaScript来进行布局:

先获取第一排中的所有图片元素。

// 设置摆放图片的固定宽度
window.onload = function(){
    imgLocation("container","box");
}
// 需要先获得屏幕有多少的图片——通过计算div的个数来获取
// 这里parent是container,content是box
function imgLocation(parent,content){
    // 将parent下所有的content全部取出
    var cparent = document.getElementById(parent);
    var ccontent = getChildElement(cparent,content);
    console.log(ccontent);
}
// 通过一个方法获取子级元素
function getChildElement(parent,content){
    // 定义一个数组存储元素
    var contentArr = [];
    var allcontent = parent.getElementsByTagName("*");
    for(var i=0;i<allcontent.length;i++){
        if(allcontent[i].className == content){
            contentArr.push(allcontent[i]);
        }
    }
    return contentArr;
}

打开控制台,看看效果:
在这里插入图片描述
可以看到已经获取到了10个元素。

接下来就需要固定每一行所摆放图片的位置和确定每一行摆放图片的张数。

// 这里parent是container,content是box
function imgLocation(parent,content){
    // 将parent下所有的content全部取出
    var cparent = document.getElementById(parent);
    var ccontent = getChildElement(cparent,content);
    // 得到每张图片的宽度
    var imgWidth = ccontent[0].offsetWidth;
    // 获取到每一排所能放置图片的个数
    var cols = Math.floor(document.documentElement.clientWidth / imgWidth);
    // 使其固定化,同时居中
    cparent.style.cssText = "width:"+imgWidth*cols+"px;";
    cparent.style.margin = "0px auto";
}

可以看到以下效果,同时布局不会因为窗体变化而变化。
在这里插入图片描述
接下来要处理一下第二行图片的位置问题了。需要获取到高度最低的图片位置,并将第二行的第一张图片插入进去。

// 创建一个数组来承载第一排中所有图片的高度
    var boxHeightArr = [];
    for(var i=0;i<ccontent.length;i++){
        if(i<cols){
            boxHeightArr[i] = ccontent[i].offsetHeight;
        }else{
            // 得到最小的高度
            var minHeight = Math.min.apply(null,boxHeightArr);
            ccontent[i].style.position = "absolute";
            ccontent[i].style.top = minHeight+"px";
        }
    }

接着刷新页面,可以发现下面的照片的确跟最低张处于同一水平高度上。
在这里插入图片描述
但有一个问题,所有的图片都在那个位置。所以仍然需要修改。
可以通过创建一个函数来获取最小高度的位置。

// 得到最小高度的图片的位置
function getMinHeightLocation(boxHeightArr,minHeight){
    // 通过遍历得到对应的位置获取i
    for(var i in boxHeightArr){
        if(boxHeightArr[i]==minHeight){
            return i;
        }
    }
}

同时调用这个函数。

// 得到最小高度的位置参数
var minIndex = getMinHeightLocation(boxHeightArr,minHeight);

接着确定左边的宽度。

// 确定左边的宽度
ccontent[i].style.left = ccontent[minIndex].offsetLeft+"px";

然后可以看到效果:
在这里插入图片描述
的确解决了问题。

但其实,前面插入的是10张图片,这里显示了8张,说明有两张也按照一样的方式插入上去了(被蓝色那张图片覆盖了)。于是可以通过刷新数组高度的变化来解决这个问题。

// 更新数组的高度 原本的高度加上新插入图片的高度
boxHeightArr[minIndex] = boxHeightArr[minIndex] + ccontent[i].offsetHeight;

再刷新一下,可以看到效果了!
在这里插入图片描述
将html文件的图片复制多一些,瀑布流的效果就很明显了。
在这里插入图片描述
接着尝试模仿加载新的图片,即类似百度图片刷到差不多底部的时候会自动加载新的图片。这时需要监听滚动条。

// 监听滚动条
    window.onscroll = function(){
        
    }

同时定义一个方法判断是否允许进行加载。

function checkFlag(){
    var cparent = document.getElementById("container");
    var ccontent = getChildElement(cparent,"box");
    // 获取最后一张图片距离顶部的高度
    var lastContentHeight = ccontent[ccontent.length-1].offsetTop;
    // 获取滚动条滚动的距离
    var scrollTop = document.documentElement.scrollTop||document.body.scrollTop;
    // 获取当前页面的高度
    var pageHeight = document.documentElement.clientHeight||document.body.clientHeight;
    // 如果满足条件,就返回true,允许加载
    if(lastContentHeight<scrollTop+pageHeight){
        return true;
    }
}

同时调用这个方法。调用这个方法前,需要模拟数据库。这里通过json模拟。

// 通过json模拟数据库
    var imgData={"data":[{"src":"11.jpg"},{"src":"12.jpg"},{"src":"13.jpg"},
                {"src":"14.jpg"},{"src":"15.jpg"},{"src":"16.jpg"}]};

调用checkFlag()方法,同时将json中的图片添加进去。

// 监听滚动条
    window.onscroll = function(){
        if(checkFlag()){
            var cparent = document.getElementById("container");
            for(var i=0;i<imgData.data.length;i++){
                // 添加数据库的图片
                // 添加div元素
                var ccontent = document.createElement("div");
                ccontent.className = "box";
                cparent.appendChild(ccontent);
                // 添加boximg
                var boxImg = document.createElement("div");
                boxImg.className = "box_img";
                ccontent.appendChild(boxImg);
                // 添加img
                var img = document.createElement("img");
                img.src = imgData.data[i].src;
                boxImg.appendChild(img);
            }
        }
    }

然后可以发现,新加载的图片并没有按照JavaScript布局进行布局,就像刚开始的布局一样。
在这里插入图片描述
所以应该重新调用一下方法。

// 监听滚动条
    window.onscroll = function(){
        if(checkFlag()){
            var cparent = document.getElementById("container");
            for(var i=0;i<imgData.data.length;i++){
                // 添加数据库的图片
                // 添加div元素
                var ccontent = document.createElement("div");
                ccontent.className = "box";
                cparent.appendChild(ccontent);
                // 添加boximg
                var boxImg = document.createElement("div");
                boxImg.className = "box_img";
                ccontent.appendChild(boxImg);
                // 添加img
                var img = document.createElement("img");
                img.src = imgData.data[i].src;
                boxImg.appendChild(img);
            }
            // 重新调用方法适应JavaScript布局
            imgLocation("container","box");
        }
    }

最终的瀑布流效果就出来了:

在这里插入图片描述
附上源码

HTML

<head>
    <meta charset="utf-8">
    <title>瀑布流练习</title>
    <link rel="stylesheet" type="text/css" href="style.css">
    <script src="app.js"></script>
</head>
<body>
    <div id="container">
        <div class="box">
            <div class="box_img">
                <img src="1.jpg" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box_img">
                <img src="2.jpg" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box_img">
                <img src="3.jpg" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box_img">
                <img src="4.jpg" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box_img">
                <img src="5.jpg" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box_img">
                <img src="6.jpg" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box_img">
                <img src="7.jpg" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box_img">
                <img src="8.jpg" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box_img">
                <img src="9.jpg" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box_img">
                <img src="10.jpg" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box_img">
                <img src="1.jpg" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box_img">
                <img src="2.jpg" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box_img">
                <img src="3.jpg" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box_img">
                <img src="4.jpg" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box_img">
                <img src="5.jpg" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box_img">
                <img src="6.jpg" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box_img">
                <img src="7.jpg" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box_img">
                <img src="8.jpg" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box_img">
                <img src="9.jpg" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box_img">
                <img src="10.jpg" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box_img">
                <img src="1.jpg" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box_img">
                <img src="2.jpg" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box_img">
                <img src="3.jpg" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box_img">
                <img src="4.jpg" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box_img">
                <img src="5.jpg" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box_img">
                <img src="6.jpg" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box_img">
                <img src="7.jpg" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box_img">
                <img src="8.jpg" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box_img">
                <img src="9.jpg" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box_img">
                <img src="10.jpg" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box_img">
                <img src="1.jpg" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box_img">
                <img src="2.jpg" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box_img">
                <img src="3.jpg" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box_img">
                <img src="4.jpg" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box_img">
                <img src="5.jpg" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box_img">
                <img src="6.jpg" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box_img">
                <img src="7.jpg" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box_img">
                <img src="8.jpg" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box_img">
                <img src="9.jpg" alt="">
            </div>
        </div>
        <div class="box">
            <div class="box_img">
                <img src="10.jpg" alt="">
            </div>
        </div>
    </div>
</body>

CSS

/* 去掉边距 */
*{
    margin: 0px;
    padding: 0px;
}
#container{
    position: relative;
}
.box{
    padding: 5px;
    float: left;
}
/* 承载图片的盒子 */
.box_img{
    padding: 5px;
    border: 1px solid #ccc;
    /* 设置阴影 */
    box-shadow: 0 0 5px #ccc; 
    /* 设置圆角 */
    border-radius: 5px;
}
.box_img img{
    width: 150px;
    height: auto;
}

JavaScript

// 设置摆放图片的固定宽度
window.onload = function(){
    imgLocation("container","box");
    
    // 通过json模拟数据库
    var imgData={"data":[{"src":"11.jpg"},{"src":"12.jpg"},{"src":"13.jpg"},
                {"src":"14.jpg"},{"src":"15.jpg"},{"src":"16.jpg"}]};
    
    // 监听滚动条
    window.onscroll = function(){
        if(checkFlag()){
            var cparent = document.getElementById("container");
            for(var i=0;i<imgData.data.length;i++){
                // 添加数据库的图片
                // 添加div元素
                var ccontent = document.createElement("div");
                ccontent.className = "box";
                cparent.appendChild(ccontent);
                // 添加boximg
                var boxImg = document.createElement("div");
                boxImg.className = "box_img";
                ccontent.appendChild(boxImg);
                // 添加img
                var img = document.createElement("img");
                img.src = imgData.data[i].src;
                boxImg.appendChild(img);
            }
            // 重新调用方法适应JavaScript布局
            imgLocation("container","box");
        }
    }
}

// 判断是否要进行加载图片
function checkFlag(){
    var cparent = document.getElementById("container");
    var ccontent = getChildElement(cparent,"box");
    // 获取最后一张图片距离顶部的高度
    var lastContentHeight = ccontent[ccontent.length-1].offsetTop;
    // 获取滚动条滚动的距离
    var scrollTop = document.documentElement.scrollTop||document.body.scrollTop;
    // 获取当前页面的高度
    var pageHeight = document.documentElement.clientHeight||document.body.clientHeight;
    // 如果满足条件,就返回true,允许加载
    if(lastContentHeight<scrollTop+pageHeight){
        return true;
    }
}

// 需要先获得屏幕有多少的图片——通过计算div的个数来获取
// 这里parent是container,content是box
function imgLocation(parent,content){
    // 将parent下所有的content全部取出
    var cparent = document.getElementById(parent);
    var ccontent = getChildElement(cparent,content);
    // 得到每张图片的宽度
    var imgWidth = ccontent[0].offsetWidth;
    // 获取到每一排所能放置图片的个数
    var cols = Math.floor(document.documentElement.clientWidth / imgWidth);
    // 使其固定化,同时居中
    cparent.style.cssText = "width:"+imgWidth*cols+"px;";
    cparent.style.margin = "0px auto";

    // 创建一个数组来承载第一排中所有图片的高度
    var boxHeightArr = [];
    for(var i=0;i<ccontent.length;i++){
        if(i<cols){
            boxHeightArr[i] = ccontent[i].offsetHeight;
        }else{
            // 得到最小的高度
            var minHeight = Math.min.apply(null,boxHeightArr);
            // 得到最小高度的位置参数
            var minIndex = getMinHeightLocation(boxHeightArr,minHeight);
            ccontent[i].style.position = "absolute";
            ccontent[i].style.top = minHeight+"px";
            // 确定左边的宽度
            ccontent[i].style.left = ccontent[minIndex].offsetLeft+"px";
            // 更新数组的高度 原本的高度加上新插入图片的高度
            boxHeightArr[minIndex] = boxHeightArr[minIndex] + ccontent[i].offsetHeight;
        }
    }
}

// 得到最小高度的图片的位置
function getMinHeightLocation(boxHeightArr,minHeight){
    // 通过遍历得到对应的位置获取i
    for(var i in boxHeightArr){
        if(boxHeightArr[i]==minHeight){
            return i;
        }
    }
}

// 通过一个方法获取子级元素
function getChildElement(parent,content){
    // 定义一个数组存储元素
    var contentArr = [];
    var allcontent = parent.getElementsByTagName("*");
    for(var i=0;i<allcontent.length;i++){
        if(allcontent[i].className == content){
            contentArr.push(allcontent[i]);
        }
    }
    return contentArr;
}
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值