JS手写系列--瀑布流布局

3 阅读1分钟

HTML

<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>瀑布流布局</title>
    <link rel="stylesheet" href="/common/css/reset.css" />
    <link rel="stylesheet" href="./index.css" />
  </head>
  <body>
    <h1>瀑布流布局</h1>
    <div class="container"></div>
    <script src="./index.js"></script>
  </body>
</html>

CSS

h1 {
  font-size: 30px;
  text-align: center;
  margin-top: 50px;
}

.container {
  width: 90%;
  /* outline: 1px solid red; */
  margin: 0 auto;
  margin-top: 30px;
  position: relative;
  min-height: 800px;
}

.item {
  width: 200px;
  /* height: 300px; */
  background-color: #ccc;
  float: left;
  /* transform: scale(0.95); */
  /* outline: 1px solid blue; */
  border-radius: 6px;
  position: absolute;
  transition: all 0.3s;
}

JS

function $(selector) {
  return document.querySelector(selector);
}
function $$(selector) {
  return document.querySelectorAll(selector);
}

var doms = {};
var columnHeights = [];


init();


function layout() {
  console.log('layout');
  function calColumns() {
    var containerWidth = doms.container.clientWidth;
    var itemWidth = 200 || doms.waterFallItems[0].clientWidth;
    var columns = Math.floor(containerWidth / itemWidth);
    var gap = (containerWidth - columns * itemWidth) / (columns - 1);
    if (gap < 10) {
      columns -= 1;
      gap = (containerWidth - columns * itemWidth) / (columns - 1);
    }
    columnHeights = new Array(columns).fill(0);
    return {
      columns,
      gap
    }
  }

  function getColumnIndex() {
    var minHeight = Math.min(...columnHeights);
    return columnHeights.indexOf(minHeight);
  }

  function setItemPosition(item, columnIndex) {
    function setLeft() {
      item.style.left = columnIndex * (200 + gap) + 'px';
    }

    function setTop() {
      item.style.top = columnHeights[columnIndex] + 'px';
      columnHeights[columnIndex] += item.clientHeight + 30;
    }

    setLeft();
    setTop();

  }
  var { columns, gap } = calColumns();
  console.log('columns', columns, 'gap', gap);
  var containerWidth = doms.container.clientWidth;
  console.log('containerWidth', containerWidth);
  console.log(columns * 200 + (columns - 1) * gap);


  for (let i = 0; i < doms.waterFallItems.length; i++) {
    var item = doms.waterFallItems[i];
    // console.log('columnHeights', columnHeights);
    var columnIndex = getColumnIndex();
    // console.log(columnIndex);
    setItemPosition(item, columnIndex);
  }

  function setContainerHeight() {
    var maxHeight = Math.max(...columnHeights);
    doms.container.style.height = maxHeight + 'px';
  }
  setContainerHeight();

}

function init() {
  doms.container = $('.container');
  for (let i = 0; i < 20; i++) {
    var item = createItem();
    doms.container.appendChild(item);
  }
  doms.waterFallItems = $$('.item');
  layout();

  window.addEventListener('resize', debounce(layout, 200));
}



function createItem() {
  function getRandomColor() {
    var letters = '0123456789ABCDEF';
    var color = '#';
    for (var i = 0; i < 6; i++) {
      color += letters[Math.floor(Math.random() * 16)];
    }
    return color;
  }
  function getRandomHeight() {
    return Math.floor(Math.random() * 200) + 100;
  }
  var item = document.createElement('div');
  item.setAttribute('class', 'item');
  item.style.backgroundColor = getRandomColor();
  item.style.height = getRandomHeight() + 'px';

  return item;
}


function debounce(fn, delay) {
  let timer = null;
  return function (...args) {
    if (timer) clearTimeout(timer);
    timer = setTimeout(() => {
      fn.apply(this, args);
    }, delay);
  }
}