Loading...

文章背景图

[学习,记录] 原生JS实现瀑布流

2022-01-27
2063
-
- 分钟

原生实现

<!DOCTYPE html>
<html lang="zh-CN">

<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>瀑布流</title>
  <style>
    ul {
      position: relative;
      margin: 0 auto;
      width: 500px;
    }

    li {
      position: absolute;
      width: 240px;
      list-style: none;
      background-color: #FCC;
    }

    li:nth-of-type(2n) {
      background-color: #FFC;
    }

    li:nth-of-type(3n) {
      background-color: #CCF;
    }

    li:nth-of-type(4n) {
      background-color: #CFF;
    }
  </style>
</head>

<body>
  <div>
    <ul>
      <li style="height: 400px;"></li>
      <li style="height: 1200px;"></li>
      <li style="height: 100px;"></li>
      <li style="height: 200px;"></li>
      <li style="height: 700px;"></li>
      <li style="height: 320px;"></li>
      <li style="height: 500px;"></li>
      <li style="height: 100px;"></li>
      <li style="height: 900px;"></li>
      <li style="height: 320px;"></li>
    </ul>
  </div>
</body>

<script>
  (function (colSpace = 20, bottomSpace = 20) {
    // 外层容器
    const container = document.querySelector("ul");
    // 所有待整理的块
    const blocks = document.querySelectorAll("li");
    // 块宽度
    const blockWidth = (function () {
      if (window.getComputedStyle) {
        return (parseFloat(getComputedStyle(container, null).width) - colSpace) / 2;
      } else {
        return (parseFloat(container.currentStyle.width) - colSpace) / 2;
      }
    })();
    let leftHeight = 0;
    let rightHeight = 0;

    function setToLeft(/** @type {HTMLElement} */ e) {
      let sty;
      if (window.getComputedStyle) {
        sty = getComputedStyle(e, null);
      } else {
        sty = e.currentStyle;
      }
      e.style.left = '0px';
      e.style.top = leftHeight + 'px';
      leftHeight += (parseFloat(sty.height) + bottomSpace);
    }

    function setToRight(/** @type {HTMLElement} */ e) {
      let sty;
      if (window.getComputedStyle) {
        sty = getComputedStyle(e, null);
      } else {
        sty = e.currentStyle;
      }

      e.style.left = (parseFloat(sty.width) + colSpace) + 'px';
      e.style.top = rightHeight + 'px';
      rightHeight += (parseFloat(sty.height) + bottomSpace);

    }

    blocks.forEach(function (e, index) {
      console.log(leftHeight, rightHeight);
      if (leftHeight <= rightHeight) {
        setToLeft(e);
      } else {
        setToRight(e);
      }
      if (leftHeight >= rightHeight) {
        container.style.height = leftHeight + 'px';
      } else {
        container.style.height = rightHeight + 'px';
      }
    })
  })();
</script>

</html>

原生瀑布流实战

<!DOCTYPE html>
<html lang="zh-CN">

<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>瀑布流实战</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    #app {
      position: relative;
      margin: 0 auto;
      width: 90%;
    }

    li {
      display: block;
      width: 100%;
      list-style: none;
    }

    li img {
      display: block;
      width: 100%;
    }
  </style>
</head>

<body>
  <div id="app">
    <ul class="block">
      <li><img data-src="https://s2.loli.net/2022/01/27/Plu5bckpgsOiXBG.jpg" /></li>
      <li><img data-src="https://s2.loli.net/2022/01/27/3wNeMhUq2ayWds7.jpg" /></li>
      <li><img data-src="https://s2.loli.net/2022/01/27/Iup7gHNKPx5GTjq.jpg" /></li>
      <li><img data-src="https://s2.loli.net/2022/01/27/AJy15ouHpjOxIvg.jpg" /></li>
    </ul>
    <ul class="block">
      <li><img data-src="https://s2.loli.net/2022/01/27/Plu5bckpgsOiXBG.jpg" /></li>
    </ul>
    <ul class="block">
      <li><img data-src="https://s2.loli.net/2022/01/27/Plu5bckpgsOiXBG.jpg" /></li>
      <li><img data-src="https://s2.loli.net/2022/01/27/3wNeMhUq2ayWds7.jpg" /></li>
    </ul>
    <ul class="block">
      <li><img data-src="https://s2.loli.net/2022/01/27/Iup7gHNKPx5GTjq.jpg" /></li>
      <li><img data-src="https://s2.loli.net/2022/01/27/AJy15ouHpjOxIvg.jpg" /></li>
    </ul>
    <ul class="block">
      <li><img data-src="https://s2.loli.net/2022/01/27/Plu5bckpgsOiXBG.jpg" /></li>
      <li><img data-src="https://s2.loli.net/2022/01/27/AJy15ouHpjOxIvg.jpg" /></li>
    </ul>
    <ul class="block">
      <li><img data-src="https://s2.loli.net/2022/01/27/Plu5bckpgsOiXBG.jpg" /></li>
      <li><img data-src="https://s2.loli.net/2022/01/27/3wNeMhUq2ayWds7.jpg" /></li>
      <li><img data-src="https://s2.loli.net/2022/01/27/AJy15ouHpjOxIvg.jpg" /></li>
    </ul>
    <ul class="block">
      <li><img data-src="https://s2.loli.net/2022/01/27/Plu5bckpgsOiXBG.jpg" /></li>
      <li><img data-src="https://s2.loli.net/2022/01/27/Iup7gHNKPx5GTjq.jpg" /></li>
    </ul>
    <ul class="block">
      <li><img data-src="https://s2.loli.net/2022/01/27/3wNeMhUq2ayWds7.jpg" /></li>
      <li><img data-src="https://s2.loli.net/2022/01/27/Iup7gHNKPx5GTjq.jpg" /></li>
      <li><img data-src="https://s2.loli.net/2022/01/27/AJy15ouHpjOxIvg.jpg" /></li>
    </ul>
    <ul class="block">
      <li><img data-src="https://s2.loli.net/2022/01/27/Plu5bckpgsOiXBG.jpg" /></li>
      <li><img data-src="https://s2.loli.net/2022/01/27/Iup7gHNKPx5GTjq.jpg" /></li>
      <li><img data-src="https://s2.loli.net/2022/01/27/AJy15ouHpjOxIvg.jpg" /></li>
    </ul>
    <ul class="block">
      <li><img data-src="https://s2.loli.net/2022/01/27/3wNeMhUq2ayWds7.jpg" /></li>
      <li><img data-src="https://s2.loli.net/2022/01/27/AJy15ouHpjOxIvg.jpg" /></li>
    </ul>
  </div>
</body>

<script>
  /**
 * 
 * @param {Number} col 瀑布流设置多少列
 * @param {Number} ccolSpace 每列之间空多少位置
 * @param {Number} bottomSpace 每一个块底部留多少位置
 * 
 */
  function waterfall(col = innerWidth < 1145 ? 2 : 3, colSpace = 20, bottomSpace = 20) {
    // 外层容器
    const container = document.querySelector("#app");

    // 所有待整理的块
    const blocks = document.querySelectorAll(".block");

    // 块宽度
    const blockWidth = (function () {
      if (window.getComputedStyle) {
        return (parseFloat(getComputedStyle(container, null).width) - (colSpace * (col - 1))) / col;
      } else {
        return (parseFloat(container.currentStyle.width) - (colSpace * (col - 1))) / col;
      }
    })();

    // 存放每一列的高度
    const heights = [];
    for (let i = 0; i < col; i++) {
      // 每一列初始赋值0
      heights[i] = 0;
    }

    // 设置块的位置
    function setLocation(/** @type {HTMLElement} */ e, /** @type {Number} */ colNumber) {
      /** @type {CSSStyleDeclaration} */
      var sty;
      // 兼容性样式获取写法
      if (window.getComputedStyle) {
        sty = getComputedStyle(e, null);
      } else {
        sty = e.currentStyle;
      }

      // 设置块的left、top、width
      e.style.cssText = `position: absolute; left: ${(blockWidth + colSpace) * colNumber}px; top: ${heights[colNumber]}px; width: ${blockWidth}px;`;

      // 累加列的高度
      heights[colNumber] += (parseFloat(sty.height) + bottomSpace);
    }

    blocks.forEach(function (e, index) {
      // 在数组中寻找最低高度所对应的列
      let isi = heights.findIndex(function (n) {
        // 获取所有列中最低的高度
        return n == Math.min(...heights);
      });
      // 传入要设置位置的块,以及要设置到的列数
      setLocation(e, isi);
    });

    container.style.height = Math.max(...heights) + 'px';
  };

  window.onload = function () {
    const imgs = document.querySelectorAll('#app img');
    let count = 0;
    Array.from(imgs).forEach((/** @type {HTMLImageElement} */ img, index, arr) => {
      img.src = img.dataset.src;
      img.addEventListener('load', function () {
        count++;
        if (count == arr.length) {
          waterfall(4);
        }
      })
    })
  }
</script>

</html>

这种图片加载方式还挺暴力的,可以使用imagesloaded这个库。

评论交流

文章目录