瀑布流布局原理及详解

瀑布流布局原理及详解,第1张

📝 个人简介

⭐ 个人主页:我是段段🙋‍
🍊 博客领域:编程基础、前端💻
🍅 写作风格:干货!干货!都是干货!
🍑 精选专栏:JavaScript
🛸 支持段段:点赞👍、收藏⭐、留言💬

文章目录 前言原生JS实现瀑布流column多列布局实现瀑布流flex属性实现瀑布流列数动态的瀑布流

前言

  在写项目的过程中,整个页面分成了3列,每列的宽度相等而高度不等,且第二行的第一个容器需要放在第一行高度最小的容器下面,所以就在网上查了下,这种布局方式叫做瀑布流布局

原生JS实现瀑布流

首先对原生JS实现瀑布流布局的原理进行分析:

瀑布流布局最大的特点就是等宽不等高使用瀑布流布局可以使页面最后一行的容器高度差距最小,所以从第二行开始,每一个容器都要放在第一行容器高度最小的下方,以此类推将所有容器(子元素)放在一个大容器(父元素)中,给父元素设置绝对定位,子元素设置相对定位,通过子元素的topleft属性值来调整其位置

首先是页面的DOM元素

<div id="wrap">
    <div class="item1">1div>
    <div class="item2">2div>
    <div class="item3">3div>
    <div class="item4">4div>
    <div class="item5">5div>
    <div class="item6">6div>
    <div class="item7">7div>
    <div class="item8">8div>
    <div class="item9">9div>
    <div class="item10">10div>
div>

然后写了点简单的css样式

* {
    margin: 0;
    padding: 0;
}

body {
    padding: 10px;
    background-color: lightgray;
}

body::-webkit-scrollbar {
    width: 4px;
    height: 1px;
}

body::-webkit-scrollbar-thumb {
    border-radius: 2px;
    background: #E0E0E0;
}

body::-webkit-scrollbar-track {
    border-radius: 10px;
    background: #FFF;
}

#wrap {
    width: 100%;
    height: calc(100vh - 20px);
    /* 父元素设置相对定位 */
    position: relative;
}

#wrap div {
    width: calc(100% / 3 - 20px / 3);
    background-color: #FFF;
    border-radius: 8px;
    /* 子元素设置绝对定位 */
    position: absolute;
    /* 初始的左、上边距都设置为0 */
    left: 0;
    top: 0;
    font-size: 40px;
    font-weight: bold;
    text-align: center;
}

#wrap div img{
    width: 100%;
    border-radius: 8px 8px 0 0;
    vertical-align: bottom
}

#wrap div p{
    font-size: 24px;
}

.item1 {
    height: 200px;
}

.item2 {
    height: 250px;
}

.item3 {
    height: 150px;
}

.item5,
.item7 {
    height: 200px;
}

.item4,
.item10 {
    height: 150px;
}

.item6 {
    height: 240px;
}

.item9 {
    height: 200px;
}

.item8 {
    height: 250px;
}

因为这个项目已经知道了整个页面被分为了3列,所以在css中已经对宽度进行了计算

接下来主要对js代码进行分析

// 通过CDN引入jQuery
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
<script>
    let divList = $('#wrap div') // 获取到需要布局显示的div容器
	divList = Array.from(divList) // 通过Array的from()方法将伪数组转化为真正的数组

    let pageW = document.documentElement.clientWidth // 获取当前屏幕的宽度
    let divW = divList[0].clientWidth // 获取一个div容器的宽度
    let cols = Math.floor(pageW / divW) // 计算一行能够放几个div容器
    let arrH = [] // 用来存储每个div容器的高度

    // 循环div容器的数组
    divList.forEach((item, index) => {
        // 1. 对下标小于一行个数的div容器进行 *** 作
        if (index < cols) {
            arrH.push(item.clientHeight) // 将div容器的高度放入数组中
            item.style.left = index * divW + index * 10 + 'px' // 同时设置每个容器的left值,第一行top都为0
        }
    })
    // 2. 对剩余的div容器进行循环
    for (let i = cols; i < divList.length; i++) {
        let minH = Math.min.apply(Math, arrH), // 获取到数组中最小的高度
            idx_min = arrH.indexOf(minH) // 查找到最小高度的下标
        divList[i].style.left = divList[idx_min].style.left // 让当前的div容器和最小下标的left值相同
        divList[i].style.top = minH + 10 + 'px' // top值在原来的最小高度上+10(为了是容器之间有一个间隙,可随意写)
        // 最小列的高度 = 当前自己的高度 + 新容器的高度 + 间隙
        arrH[idx_min] = minH + divList[i].clientHeight + 10 
    }
</script>

实现的结果图如下


可以放置图片查看效果

column多列布局实现瀑布流

首先分析下实现原理:

因为是用css的column布局实现的,所以就没有用到js代码

主要使用了column-countcolumn-gap属性,column-count属性用来设置列数,column-gap属性用来设置列于列之间得间距

页面的DOM结构和上种方式是一样的,主要对css样式进行了修改

* {
    margin: 0;
    padding: 0;
}

body {
    padding: 5px;
    background-color: lightgray;
}

body::-webkit-scrollbar {
    width: 4px;
    height: 1px;
}

body::-webkit-scrollbar-thumb {
    border-radius: 2px;
    background: #E0E0E0;
}

body::-webkit-scrollbar-track {
    border-radius: 10px;
    background: #FFF;
}

/* 使用column多列布局 */
/* 
    主要使用了 column-count 和 column-gap 属性
*/
#wrap {
    width: 100%;
    height: calc(100vh - 20px);
    column-count: 3; /* 列数 */
    column-gap: 10px; /* 列与列之间的距离 */
}

#wrap div {
    background-color: #FFF;
    border-radius: 8px;
    font-size: 40px;
    font-weight: bold;
    text-align: center;
    margin-bottom: 10px;
}

#wrap div img{
    width: 100%;
    border-radius: 8px 8px;
    vertical-align: bottom;
}

#wrap div p{
    font-size: 24px;
}

.item1 {
    height: 200px;
}

.item2 {
    height: 250px;
}

.item3,
.item5,
.item7 {
    height: 200px;
}

.item4,
.item10 {
    height: 150px;
}

.item6{
    height: 240px;
}
.item9 {
    height: 100px;
}

.item8 {
    height: 250px;
}

实现效果如下


但是可以看到数字为7的模块被截断,然后选择放置图片看下效果


放置图片显示效果还可以,没有出现截断的情况

column-count对浏览器兼容性不是特别好,如下

flex属性实现瀑布流

首先分析下实现原理:

因为是用css的flex布局实现的,所以就没有用到js代码

将大容器(父元素)的display设置为flex,然后使用flex-flow属性,设置为:flex-flow: column wrap;

flex-flow 作用是使d性项目按列显示,并在需要时换行

flex-flow 属性是以下属性的简写属性:

flex-directionflex-wrap

页面的DOM结构和上种方式是一样的,主要对css样式进行了修改

/* 去掉了大小容器的定位样式,将大容器设置为flex布局,并设置flex-flow属性 */
* {
    margin: 0;
    padding: 0;
}

body {
    padding: 5px;
    background-color: lightgray;
}

body::-webkit-scrollbar {
    width: 4px;
    height: 1px;
}

body::-webkit-scrollbar-thumb {
    border-radius: 2px;
    background: #E0E0E0;
}

body::-webkit-scrollbar-track {
    border-radius: 10px;
    background: #FFF;
}

/* 去掉了大小容器的定位样式,将大容器设置为flex布局,并设置flex-flow属性 */
/* 
    flex-flow属性是 flex-direction 和 flex-wrap 属性的简写形式
    flex-direction 控制元素的方向顺序
    flex-wrap 控制元素在必要时折行
*/
#wrap {
    width: 100%;
    height: calc(100vh - 20px);
    display: flex;
    flex-flow: column wrap; 
}

#wrap div {
    width: calc(100% / 3 - 20px / 3);
    background-color: #FFF;
    border-radius: 8px;
    font-size: 40px;
    font-weight: bold;
    text-align: center;
    margin-top: 10px;
    margin-right: calc(20px / 3)
}

#wrap div img{
    width: 100%;
    border-radius: 8px 8px 0 0;
    vertical-align: bottom;
}

#wrap div p{
    font-size: 24px;
}

.item1 {
    height: 200px;
}

.item2 {
    height: 250px;
}

.item3,
.item5,
.item7 {
    height: 200px;
}

.item4,
.item10 {
    height: 150px;
}

.item6{
    height: 240px;
}
.item9 {
    height: 100px;
}

.item8 {
    height: 250px;
}
}

实现的结果图如下


可以放置图片查看效果


flex-flow对浏览器的兼容性也不是特别好,但是相对column-count好一点,如下


小结: 原生js的展示是以行展示,而flex布局和column布局是以列进行展示,可以根据项目需求进行选择

列数动态的瀑布流

第一种方式实现的是列数固定的布局,所以当列数可以任意指定时,上述方法就不再适用了

动态列数的DOM结构和样式和第一种方式是一样的,只有js代码略有不同

<script>
    let divList = $('#wrap div')
    divList = Array.from(divList) // 获取DOM节点,并转化为数组

    let pageW = document.documentElement.clientWidth
    let cols = 4 // 动态设置列数
    let divW = parseInt((pageW - (cols + 1) * 10) / cols) // 计算每一个容器div的宽度并取整
    let arrH = []

    divList.forEach((item, index) => {
        if (index < cols) {
            arrH.push(item.clientHeight)
            item.style.left = index * divW + index * 10 + 'px'
        }
        item.style.width = divW + 'px' // 给每一个div容器设置宽度
    })
    for (let i = cols; i < divList.length; i++) {
        let minH = Math.min.apply(Math, arrH),
            idx_min = arrH.indexOf(minH)
        divList[i].style.left = divList[idx_min].style.left
        divList[i].style.top = minH + 10 + 'px'
        arrH[idx_min] = minH + divList[i].clientHeight + 10
    }
</script>

实现的结果图如下


总的来说,瀑布流布局就是为了节省页面展示的空间

有看不懂的地方欢迎留言~~

欢迎分享,转载请注明来源:内存溢出

原文地址: https://www.outofmemory.cn/web/1323055.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-12
下一篇 2022-06-12

发表评论

登录后才能评论

评论列表(0条)

保存