HOME/Articles/

瀑布流布局

Article Outline

瀑布流布局

<!--more-->

瀑布流:每个内容的宽度相等,高度是随机的 布局的基本原则,第一排排满之后,下面的元素将放到高度最短的那一列下面

实现的基本思路:

  • 需要创建一个数组,这个数组存储的每一项都为对应列的高度,而下标就为当前的列
  • 需要得到每个元素的宽度

实现举例:

<style>
        .content {
            position: relative;
        }
        .item {
            /*绝对定位,并且每个元素的宽度是一定的*/
            position: absolute;
            width: 200px;
            margin-right: 10px;
            margin-top:  10px;
            transition: all 1s;
        }
        .h1 {
            height: 200px;
            background: #f4b300;
        }
        .h2 {
            height: 300px;
            background: #691bbb;
        }
        .h3 {
            height: 400px;
            background: #006ac1;
        }
    </style>
</head>
<body>
     <div class="content">
         <div class="item h1">1</div>
         <div class="item h3">2</div>
         <div class="item h2">3</div>
         <div class="item h2">4</div>
         <div class="item h3">5</div>
         <div class="item h1">6</div>
         <div class="item h2">7</div>
         <div class="item h3">8</div>
         <div class="item h1">9</div>
         <div class="item h2">10</div>
         <div class="item h3">11</div>
         <div class="item h3">12</div>
         <div class="item h2">13</div>
         <div class="item h1">14</div>
     </div>

结构和样式如上,h1,h2,h3用来模拟随机的高度。 JS部分如下:

     <script src="../jquery-3.2.1.min.js"></script>
     <script>
//         创建数组
         var itemArr = [];
         //得到数组一共有多少项,即要排列的元素到底有几列,可以通过content的宽度除以item的宽度,然后进行取整就能得到总共有多少列
         var itemColumn = parseInt($('.content').width() / $('.item').width());
//         console.log(itemColumn)
         //进行数组的初始化,有itemColumn项,每项都先设为0,表示当前没有元素,高度为0
         for (var i = 0; i < itemColumn; i ++) {
            itemArr[i] = 0;
         }
         //数组初始化完毕,然后涉及到需要得到数组中值最小的一项,以及要得到最小的这一项的下标,可以使用Math.min和indexOf()两个方法
         //进行遍历所有的item,将每个item放到当前高度最短的那一列的下边
         $('.item').each(function () {
             var minHeight = Math.min.apply(null,itemArr);//数组中值最小的一项,即高度最短的那一列的高度值
             var minIndex = itemArr.indexOf(minHeight); // 对应列的下标
             $(this).css({
                 left: minIndex * $('.item').outerWidth(true), //这个outerWidth,有true代表包括margin,不写true代表只包括border
                 top: minHeight,
             })
             itemArr[minIndex] += $(this).outerHeight(true); //放置完当前遍历元素时,将相应的高度加到当前列的高度上
//             console.log('h',minHeight)
//             console.log('i',minIndex);
         })
     </script>

代码的整体思路已经很清晰了,但是有地方需要注意:

  • 涉及到需要得到数组中值最小的一项,以及要得到最小的这一项的下标,可以使用Math.min和indexOf()两个方法。使用Math.min要结合apply()
  • $('.item').outerWidth(true)

然后基本效果就达到了,但是需要监听窗口大小改变的事件,如果窗口大小改变,重新排列一下。所以我们封装一下我们得到的代码。加上监听事件

         waterFall(); //页面初始化时先执行一次出现布局
         $(window).on('resize',function () { // 监听浏览器窗口大小改变的事件
             waterFall();
         })


        function waterFall() {
            //         创建数组
            var itemArr = [];
            //得到数组一共有多少项,即要排列的元素到底有几列,可以通过content的宽度除以item的宽度,然后进行取整就能得到总共有多少列
            var itemColumn = parseInt($('.content').width() / $('.item').width());
//         console.log(itemColumn)
            //进行数组的初始化,有itemColumn项,每项都先设为0,表示当前没有元素,高度为0
            for (var i = 0; i < itemColumn; i ++) {
                itemArr[i] = 0;
            }
            //数组初始化完毕,然后涉及到需要得到数组中值最小的一项,以及要得到最小的这一项的下标,可以使用Math.min和indexOf()两个方法
            //进行遍历所有的item,将每个item放到当前高度最短的那一列的下边
            $('.item').each(function () {
                var minHeight = Math.min.apply(null,itemArr);//数组中值最小的一项,即高度最短的那一列的高度值
                var minIndex = itemArr.indexOf(minHeight); // 对应列的下标
                $(this).css({
                    left: minIndex * $('.item').outerWidth(true), //这个outerWidth,有true代表包括margin,不写true代表只包括border
                    top: minHeight,
                })
                itemArr[minIndex] += $(this).outerHeight(true); //放置完当前遍历元素时,将相应的高度加到当前列的高度上
//             console.log('h',minHeight)
//             console.log('i',minIndex);
            })
        }

此时窗口大小改变时也会相应的重新布局了。还可以进一步封装代码,创建一个对象,把要执行的代码return出来,函数体放到对象内部的属性中。

         var begin = {
             run: run,
         };
         begin.run();
         function run () {
             function waterFall() {
                 //         创建数组
                 var itemArr = [];
                 //得到数组一共有多少项,即要排列的元素到底有几列,可以通过content的宽度除以item的宽度,然后进行取整就能得到总共有多少列
                 var itemColumn = parseInt($('.content').width() / $('.item').width());
//         console.log(itemColumn)
                 //进行数组的初始化,有itemColumn项,每项都先设为0,表示当前没有元素,高度为0
                 for (var i = 0; i < itemColumn; i ++) {
                     itemArr[i] = 0;
                 }
                 //数组初始化完毕,然后涉及到需要得到数组中值最小的一项,以及要得到最小的这一项的下标,可以使用Math.min和indexOf()两个方法
                 //进行遍历所有的item,将每个item放到当前高度最短的那一列的下边
                 $('.item').each(function () {
                     var minHeight = Math.min.apply(null,itemArr);//数组中值最小的一项,即高度最短的那一列的高度值
                     var minIndex = itemArr.indexOf(minHeight); // 对应列的下标
                     $(this).css({
                         left: minIndex * $('.item').outerWidth(true), //这个outerWidth,有true代表包括margin,不写true代表只包括border
                         top: minHeight,
                     })
                     itemArr[minIndex] += $(this).outerHeight(true); //放置完当前遍历元素时,将相应的高度加到当前列的高度上
//             console.log('h',minHeight)
//             console.log('i',minIndex);
                 })
             }
            return (function () {
                waterFall(); //页面初始化时先执行一次出现布局
                $(window).on('resize',function () { // 监听浏览器窗口大小改变的事件
                    waterFall();
                })
            })();
         }

封装代码如上所示,把函数体放到run()中,作为值传递给begin对象的run属性,return的是包含我们想要执行的代码的立即执行函数,这样我们想要开始的时候,只需要调用begin对象的run属性即可。