简明瀑布流算法

图片类网站经常用到瀑布流的形式来排列自己的图片,例如pinterest, 花瓣网。有很多开源的jQuery框架可以实现瀑布流,但是比较复杂。这篇文章主要讲诉图片类瀑布流的布局组织的算法,用纯js实现。

HTML

JS

//main.js
(function () {
  var COLS = 5;
  var ITEMWIDTH = 236;
  var GUTTERWIDTH = 15;
  var columnHeights;


  var button = document.getElementsByTagName("button")[0];


  // Number of columns is 5, and init heights array of columns.
  function resetHeights() {
    columnHeights = [];
    for (var i = 0; i < COLS; i++) {
      columnHeights.push(0);
    }
  }


  // main function to load images
  function loadImages() {
    var imageArr = getImages();
    var html = "";
    for (var i = 0; i < imageArr.length; i++) {
      var _div = '<div class="item">';
      var _img = '<img src="' + imageArr[i] + '">';
      _div += _img + "</div>";
      html += _div;
    }
    var container = document.getElementsByClassName("container")[0];
    container.innerHTML = html;
    console.log(html);


    // after images loaded.
    setTimeout(placeItems, 1000);
  }
  // get images source array.
  function getImages() {
    var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
    var imageArr = [];
    var baseUri = "http://myst729.github.io/Waterfall/img/";
    for (var i = 0; i < arr.length; i++) {
      var img_src = baseUri + arr[i] + ".jpg";
      imageArr.push(img_src);
    }
    return imageArr;
  }


  // get left of the item
  function getItemLeft(key) {
    var left = 0;
    // COLS
    left = (key % COLS) * (ITEMWIDTH + GUTTERWIDTH);
    return left;
  }


  //
  function placeItems() {
    resetHeights();
    var items = document.getElementsByClassName("item");
    for (var index in items) {
      columnIndex = getMinKey(columnHeights);
      columnHeight = columnHeights[columnIndex];


      items[index].style.left = getItemLeft(columnIndex) + "px";
      items[index].style.top = columnHeight + "px";
      columnHeights[columnIndex] =
        columnHeight + GUTTERWIDTH + items[index].offsetHeight;
      console.log(columnHeights);
    }
  }


  // get minimal value index of an array.
  function getMinKey(arr) {
    var key = 0;
    var min = arr[0];
    for (var i = 0; i < arr.length; i++) {
      if (arr[i] < min) {
        min = arr[i];
        key = i;
      }
    }
    return key;
  }
  button.addEventListener("click", loadImages);
})();

要点

  1. 项目item的定位

    • item的定位: position: absolute;
    • item父级元素contianer的定位:position: relative;
  2. 假设一定宽度内的列数为固定值5

  3. item的放置方式

    • 对于第一行,top值为0;
    • 对于以后的行,每次新增的item,自动补在高度最小的列,并记录下该列为第几列columnIndex;
    • 根据columnIndex可以计算出item的left,根据columnIndex对应的列高可以计算出item的top。
  4. 列高度columnHeights是一个有5个元素的数组。

简化

本文关注主要问题,即布局问题,简化(省略)了以下关注点

  • 计算一定宽度内可放置的列数
  • 调整浏览器窗口大小时,item重新布局
  • 鼠标向下滚动事件
  • ajax
关于本文如您有任何想法和意见,欢迎与我们联系,邮箱地址zhi@uqugu.com
您对本文有什么看法,喜欢或者不喜欢都可以发表意见。