瀑布流布局的实现

        瀑布流布局视觉表现为参差不齐的多栏布局,随着页面滚动条向下滚动,这种布局还会不断加载数据块并附加至当前尾部

        ​​ 瀑布流的实现方法决定了它的元素排序,具体请看我这篇推文。

纯CSS实现:multi-column多列布局

         multi-column使用的是CSS3里的columns属性。兼容性在老版本浏览器上几乎不行。

        HTML代码:

<body>
    <div class="container">
        <div class="item">
            <img  src="img/bg1.jpg" alt="" />
        </div>
        <div class="item">
            <img  src="img/bg2.jpg" alt="" />
        </div>
        <div class="item">
            <img  src="img/bg3.jpg" alt="" />
        </div>
        <div class="item">
            <img  src="img/bg4.jpeg" alt="" />
        </div>
        <div class="item">
            <img  src="img/bg5.jpg" alt="" />
        </div>
        <div class="item">
            <img  src="img/bg6.jpg" alt="" />
        </div>
        <div class="item">
            <img  src="img/bg7.jpg" alt="" />
        </div>
    </div>
</body>

         此时只需要加上CSS样式即可实现

<style>
    .container {
        margin: 0 auto;
        width: 1000px;
        column-count: 3; /* 列数 */
        column-gap: 20px; /* 列间距 */
    }
    .item {
        margin-bottom: 10px;
        /* 防止多列布局,分页媒体和多区域上下文中的意外中断 */
        break-inside: avoid;
    }
    .item img{
        width: 100%;
        height:100%;
    }
</style>

        加上3列的css属性后,元素就会按照从上到下从左到右进行排列了。

        缺点:瀑布流的优点动态加载几乎无效(因为它一列一列从上往下)

        补充的CSS属性:

  • column-gap 元素之间的间隙
  • column-width 每一列的宽度

纯Css实现:grid-template-rows属性

        CSS 新属性 grid-template-rows: masonry 轻松实现瀑布流布局,一行代码即可搞定。

        兼容性?几乎没有。

        感兴趣自己去看看,这里不介绍了。

纯CSS实现:flex

  1. flex 实现瀑布流需要将最外层元素设置为 display: flex
  2. flex-flow:column wrap 使其纵向排列并且自动换行
  3. 最外层设置 height: 100vh 填充屏幕的高度,也可以设置为单位为 px 的高度,来容纳子元素
  4. 每一列的宽度可用 calc 函数来设置,即 width: calc(100%/3 - 20px)。分成等宽的 3 列减掉左右两遍的 margin 距离
<style>
    .container {
        display: flex;  
        flex-flow: column wrap;
        height: 100vh;
      }
      .item {
        margin: 10px;
        width: calc(100%/3 - 20px);
      }
      .item img{
        width: 100%;
        height:100%;
      }
</style>

        但是一拖拽窗口,就会发生变化。为什么呢?我们看代码,每个元素的宽度都被我们固定为三分之一宽度(包括间距)。但是每个元素(可以理解为图片)它们的宽高比并不一样。这也使得每一列能包含的元素数量会随着宽度的改变而改变。

               

JS实现

        思路:将内容宽度一致,高度不一致的图片,从左至右排列,一行内容排满后,下一张就会按顺序排在最短的内容后,以此类推。

<html lang="en">
    <body>
        <div id="container">
            <div class="box">
                <div class="box-img">
                    <img src="./img/bg1.png" alt="">
                </div>
            </div>
            <div class="box">
                <div class="box-img">
                    <img src="./img/bg2.png" alt="">
                </div>
            </div>
            <div class="box">
                <div class="box-img">
                    <img src="./img/bg3.png" alt="">
                </div>
            </div>
            <div class="box">
                <div class="box-img">
                    <img src="./img/bg4.png" alt="">
                </div>
            </div>
            <div class="box">
                <div class="box-img">
                    <img src="./img/bg5.png" alt="">
                </div>
            </div>
            <div class="box">
                <div class="box-img">
                    <img src="./img/bg6.png" alt="">
                </div>
            </div>
            <div class="box">
                <div class="box-img">
                    <img src="./img/bg7.png" alt="">
                </div>
            </div>
    </body>
</html>

         CSS样式:

<style>
    /*让图片向左浮动*/
    .box {
        float: left;
    }

    /*定位*/
    .container {
        position: relative;
    }

    .box-img {
        width: 150px;
        padding: 5px;
    }

    /*让图片与图片容器宽度相等*/
    .box-img img {
        width: 100%;
    }
</style>

        JS部分:

        其实很简单,就是先把每一行的元素存到数组去,并找出高度最小的那个元素,储存它的索引,并从第二行开始逐个改变每个元素 的绝对定位的TLBR值。

<script>
    window.onload = function () {
        imgLocation('container', 'box')
    }

    //获取到所有要摆放的图片
    function imgLocation(parent, content) {
        var cparent = document.getElementById(parent)
        // cparent 下的所有的第一层的子容器 box
        var ccontent = getChildElement(cparent, content)  //[装了20个div]

        //找从谁开始是需要被摆放位置的
        var winWidth = document.documentElement.clientWidth //获取视窗的宽度
        var imgWidth = ccontent[0].offsetWidth              //获取图片盒子的宽度
        var num = Math.floor(winWidth / imgWidth)           //向下取整

        // 操作第 num+1 张图
        var BoxHeightArr = []
        for (var i = 0; i < ccontent.length; i++) {
            // 前num张只要计算高度
            if (i < num) {
                BoxHeightArr[i] = ccontent[i].offsetHeight
            } else {
                //我们要操作的Box
                var minHeight = Math.min.apply(null, BoxHeightArr)
                var minIndex = BoxHeightArr.indexOf(minHeight)

                ccontent[i].style.position = 'absolute'
                ccontent[i].style.top = minHeight + 'px'
                ccontent[i].style.left = (imgWidth * minIndex) + 'px'

                //更新最矮的那一列的高度
                BoxHeightArr[minIndex] = BoxHeightArr[minIndex] + ccontent[i].offsetHeight
            }
        }
    }


    function getChildElement(parent, content) {
        var contentArr = []
        var allContent = parent.getElementsByTagName('*') //[xxxx数组]
        //遍历allContent 把中其类名为 content 的容器都存到contentArr数组中
        for (var i = 0; i < allContent.length; i++) {
            //当前这个容器的类名是否为 content
            if (allContent[i].className == content) {
                contentArr.push(allContent[i])
            }
        }
        return contentArr
    }
</script>

插件实现

        masonry.js 

        如果在vue项目里想引用的话,可以:

npm install masonry-layout --save
import Masonry from "masonry-layout"; // Vue项目的引入方式

creatd() {
  var grid = this.$refs.gridContainer;
  var msnry = new Masonry(grid, {
    // options...
    itemSelector: ".grid-item",
    columnWidth: 300,
  });
}

我的推荐

        使用vue-grid-layout网格布局插件,它也能给你一个瀑布布局

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值