瀑布流布局 原生js

430 阅读2分钟

首先,简要介绍下所谓的瀑布流布局。

瀑布流布局,是比较流行的一种网站页面布局,视觉表现为参差不齐的多栏布局,随着页面滚动条向下滚动,这种布局还会不断加载数据块并附加至当前尾部。最早采用此布局的网站是Pinterest,逐渐在国内流行开来。例如蘑菇街

思路:通过js实现瀑布流布局的主要思路是通过计算出第一行图片的最小高度后,将第二行图片按照第一行图片高度由低到高依次排列在第一行图片下方,以此类推,从而实现瀑布流布局。接下来我将js实现瀑布流布局的方法逐步分解:

我们先来看视图实现效果:

1. 如下图所示,当图片占满浏览器窗口宽度时自动换行,第七张图片排列位置如下。

image.png 2. 接下来我们要做的就是将第七张照片移到第一排高度最低的图片也就是第三张或第六张图片的下方(图片3与图片6等高):

image.png 3.随后,更新图片最小高度,将下一张图片放置更新后的图片最小高度下方,以此类推实现瀑布流布局。

image.png

image.png 接下来,我们来看实现代码:

目录结构如下:

image.png

index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      * {
        margin: 0;
        padding: 0;
      }
      .flowLayout {
        white-space: wrap;
      }
      .flowLayout > div {
        float: left; 
        padding: 10px;
        display: flex;
        justify-content: center;
        align-items: center;
      }
      .flowLayout > div > img {
        width: 300px;
      }
      .flowLayout > div > span {
        color: #16fb29;
        position: absolute;
        font-size: 30px;
      }
    </style>
  </head>
  <body>
    <div class="flowLayout">
      <div>
        <span>1</span>
        <img src="../assets/01.jpeg" alt="" />
      </div>
      <div>
        <span>2</span>
        <img src="../assets/02.jpeg" alt="" />
      </div>
      <div>
        <span>3</span>
        <img src="../assets/09.jpeg" alt="" />
      </div>
      <div>
        <span>4</span>
        <img src="../assets/08.jpeg" alt="" />
      </div>
      <div>
        <span>5</span>
        <img src="../assets/04.jpeg" alt="" />
      </div>
      <div>
        <span>6</span>
        <img src="../assets/06.jpeg" alt="" />
      </div>
      <div>
        <span>7</span>
        <img src="../assets/07.jpeg" alt="" />
      </div>
      <div>
        <span>8</span>
        <img src="../assets/05.jpeg" alt="" />
      </div>
      <div>
        <span>9</span>
        <img src="../assets/03.jpeg" alt="" />
      </div>
      <div>
        <span>10</span>
        <img src="../assets/10.jpeg" alt="" />
      </div>
      <div>
        <span>11</span>
        <img src="../assets/11.jpeg" alt="" />
      </div>
      <div>
        <span>12</span>
        <img src="../assets/12.jpeg" alt="" />
      </div>
      <div>
        <span>13</span>
        <img src="../assets/13.jpeg" alt="" />
      </div>
      <div>
        <span>14</span>
        <img src="../assets/14.jpeg" alt="" />
      </div>
      <div>
        <span>15</span>
        <img src="../assets/15.jpeg" alt="" />
      </div>
      <div>
        <span>16</span>
        <img src="../assets/16.jpeg" alt="" />
      </div>
      <div>
        <span>17</span>
        <img src="../assets/17.jpeg" alt="" />
      </div>
      <div>
        <span>18</span>
        <img src="../assets/18.jpeg" alt="" />
      </div>
      <div>
        <span>19</span>
        <img src="../assets/19.jpeg" alt="" />
      </div>
      <div>
        <span>20</span>
        <img src="../assets/20.jpeg" alt="" />
      </div>
      <div>
        <span>21</span>
        <img src="../assets/21.jpeg" alt="" />
      </div>
      <div>
        <span>22</span>
        <img src="../assets/22.jpeg" alt="" />
      </div>
      <div>
        <span>23</span>
        <img src="../assets/23.jpeg" alt="" />
      </div>
      <div>
        <span>24</span>
        <img src="../assets/24.jpeg" alt="" />
      </div>
      <div>
        <span>25</span>
        <img src="../assets/25.jpeg" alt="" />
      </div>
      <div>
        <span>26</span>
        <img src="../assets/26.jpeg" alt="" />
      </div>
      <div>
        <span>27</span>
        <img src="../assets/27.jpeg" alt="" />
      </div>
      <div>
        <span>28</span>
        <img src="../assets/28.jpeg" alt="" />
      </div>
      <div>
        <span>29</span>
        <img src="../assets/29.jpeg" alt="" />
      </div>
      <div>
        <span>30</span>
        <img src="../assets/30.jpeg" alt="" />
      </div>
    </div>
    <script src="./index.js"></script>
  </body>
</html>

index.js

window.onload = function () {
  reset();
};

window.onresize = function () {
  reset();
};

function reset() {
  // 获取主容器的宽度
  var content = document.getElementsByClassName("flowLayout")[0];
  var contentWidth = content.offsetWidth;
  console.log("contentWidth", contentWidth);

  // 获取图片宽度
  var imgs = content.children;
  var imgWidth = imgs[0].offsetWidth;
  console.log("imgWidth", imgWidth);

  // 一行图片数量
  var num = Math.floor(contentWidth / imgWidth);
  console.log("num", num);

  // 获取第一行图片的高度
  var arrHeight = [];
  for (let i = 0; i < imgs.length; i++) {
    // 第一行图片
    if (i < num) {
      imgs[i].style.top = 0;
      imgs[i].style.left = `${i * imgWidth}px`;
      arrHeight.push(imgs[i].offsetHeight);
    } else {
      let obj = {
        minH: arrHeight[0],
        minI: 0,
      };
      obj.minH = Math.min.apply(null, arrHeight);
      console.log("obj.minH", obj.minH);
      for (let j = 0; j < arrHeight.length; j++) {
        if (obj.minH === arrHeight[j]) {
          obj.minI = j;
        }
      }
      imgs[i].style.position = "absolute";
      imgs[i].style.top = `${obj.minH}px`;
       // imgs[i].style.left = `${obj.minI * imgWidth}px`;
      imgs[i].style.left = `${imgs[obj.minI].offsetLeft}px`;

      // 更新最短高度
      arrHeight[obj.minI] = arrHeight[obj.minI] + imgs[i].offsetHeight;
    }
  }
}

总结:

  1. window.onresize必不可少,否则在浏览器窗口变化后瀑布流布局无法动态更新。
  2. 如下图所示,第一行图片也需要进行定位,否则当浏览器窗口变化后第一行图片会因为定位数据不对导致布局出现问题。

image.png

image.png

3.将图片进行定位时需要加上单位。

好啦,今天的分享先到这里,后续会分享瀑布流布局的其他实现方法,如有不对之处还请各位大佬不吝赐教,多谢~