Bootstrap和Masonry在网格底部有空白的情况下添加空白div。

9

我正在使用masonry + bootstrap,注意到当我有一个三列网格,然后有10个项目时,它会显示一个3×4的网格,底部有2个空白空间。 我如何自动添加2个空的div在底部来填充它,而不是那些空白空间? 因此,总共的div将变为12个,在其中2个div只是空的?

这不应该固定为3列,而是应该在检测到可以填充N个空div时动态添加空div。 应适用于加载和调整大小。

由于它们都具有相同的宽度和高度(框/正方形类型),所以.item的大小不会有问题。

我制作了jsFiddle,可以在最后一行的空白处添加填充物。 这也通过使用layoutComplete事件在调整大小时工作。 但是问题是,每次调整大小时,它都会添加新的填充物。

尝试调整到不同的大小,您会注意到它不断添加填充物。

此外,以下是代码。

HTML

<input type="hidden" name="hfTotalGridItems" id="hfTotalGridItems" value="10" />
<div class="grid">
    <div class="item">
        <div>lorem</div>
    </div>
    <div class="item">
        <div>lorem</div>
    </div>
    <div class="item">
        <div>lorem</div>
    </div>
    <div class="item">
        <div>lorem</div>
    </div>
    <div class="item">
        <div>lorem</div>
    </div>
    <div class="item">
        <div>lorem</div>
    </div>
    <div class="item">
        <div>lorem</div>
    </div>
    <div class="item">
        <div>lorem</div>
    </div>
    <div class="item">
        <div>lorem</div>
    </div>
    <div class="item">
        <div>lorem</div>
    </div>
</div>
<div class="result"></div>

CSS

.grid {
    margin: 0 auto;
}
.item {
    margin-bottom: 20px;
    border: 1px solid red;
    height: 80px;
    width: 80px;        
}
.filler {
    background-color: #999;
    border: 1px solid blue;
}

JQuery

$(function () {
    function calculateRows() {
        var lisInRow = 0;
        var $item = $('.grid .item');
        var $grid = $('.grid');
        var itemWidth = $('.grid .item').width();
        var itemHeight = $('.grid .item').height();

        $item.each(function () {
            if ($(this).prev().length > 0) {
                if ($(this).position().top != $(this).prev().position().top) return false;
                lisInRow++;
            } else {
                lisInRow++;
            }
        });

        var lisInLastRow = $item.length % lisInRow;
        if (lisInLastRow == 0) lisInLastRow = lisInRow;

        $('.result').html('No: of lis in a row = ' + lisInRow + '<br>' + 'No: of lis in last row = ' + lisInLastRow);

        if (lisInLastRow < lisInRow) {
            var $clonedItem = $('.grid .item:last-child').clone().empty().css({
                width: itemWidth,
                height: itemHeight
            }).addClass('filler');
            $grid.append($clonedItem).masonry('appended', $clonedItem);

        } else {
            if (newTotal > $('#hfTotalGridItems').val()) {
                $grid.masonry('remove', $('.grid .item.filler'));
                $grid.masonry();
            }
        }
    }

    var $grid = $('.grid');

    $grid.masonry({
        itemSelector: '.item',
        isFitWidth: true,
        gutter: 20
    });

    $grid.masonry('on', 'layoutComplete', function (event) {
        calculateRows(event.length);
    });

    $grid.masonry();
});

更新的代码现在可以计算一行中的列数。 - basagabi
2个回答

5

你需要检查两件事情

  1. If the number of original boxes is evenly divisible by the number of boxes in the first row (originalBoxs % lisInRow === 0).
  2. If the number of boxes is greater then a max allowed number of boxes. You can calculate the max allowed boxes as below

    var totalAllowed = lisInRow;
    while (totalAllowed < originalBoxs) {
       totalAllowed += lisInRow;
    }
    
如果是真的,那么你应该删除所有多余的框。否则添加填充框。这里是一个更新的jsFiddle
下面是我添加的更新的jQuery代码。
$(function () {

    // remember the original box lenth. 
    var $item = $('.grid .item');
    var originalBoxs = $item.length;

    function calculateRows() {

        var lisInRow = 0;
        var $item = $('.grid .item');
        var $grid = $('.grid');
        var itemWidth = $('.grid .item').width();
        var itemHeight = $('.grid .item').height();

        // calculate how many boxes are in the first row. 
        $item.each(function () {
            if ($(this).prev().length > 0) {
                if ($(this).position().top != $(this).prev().position().top) return false;
                lisInRow++;
            } else {
                lisInRow++;
            }
        });

        // calculate how many boxes are in the last row. 
        var lisInLastRow = $item.length % lisInRow;

        $('.result').html('No: of lis in a row = ' + lisInRow + '<br>' + 'No: of lis in last row = ' + lisInLastRow);

        // the total allowed boxes on the page. 
        var totalAllowed = lisInRow;
        while (totalAllowed < originalBoxs) {
            totalAllowed += lisInRow;
        }

        if (($item.length > originalBoxs && originalBoxs % lisInRow === 0) || ($item.length > totalAllowed)) {
            // if the number of original boxes evenly divides into the number of boxes in a row.
            // or the number of boxes on the page is past the max allowed. 
            // remove any filler boxes. 
            var boxesToDelete = $('.grid .item.filler');
            var deleteBoxes = $item.length - totalAllowed;
            for (var i = 0; i < deleteBoxes; i++) {
                // delete unnesecary boxes. 
                $grid.masonry('remove', boxesToDelete[boxesToDelete.length - i - 1]);
            }
        } else if (lisInLastRow !== 0) {
            // if the last row does not equal 0 and the number of boxes is less then the original + the first row
            // then fill it in with new boxes. 
            var $clonedItem = $('.grid .item:last-child').clone().empty().css({
                width: itemWidth,
                height: itemHeight
            }).addClass('filler');
            $grid.append($clonedItem).masonry('appended', $clonedItem);    
        }

    }

    var $grid = $('.grid');

    $grid.masonry({
        itemSelector: '.item',
        isFitWidth: true,
        gutter: 20
    });

    $grid.masonry('on', 'layoutComplete', function (event) {
        calculateRows(event.length);
    });

    $grid.masonry();
});

尽管如此,它仍然不起作用...以下是重新创建的步骤:1)调整大小为5列网格。2)调整大小为8列网格,注意到填充物被添加3)调整大小为7列网格,注意到底部添加了填充物。4)调整大小为6列网格,注意到底部添加了更多的填充物。5)调整大小为5列网格,所有填充物都被移除。 - basagabi
@user1781041明白了。所以我们需要做的是计算允许的最大箱数,并确保填充箱不会超过此最大箱数。我会更新上面的答案。 - jjbskir
这个完美运行!谢谢@jjbskir!这是使用精确的砌体功能进行附加。我仍然需要更多时间来颁发奖励 :) - basagabi

3

这里有一个稍微不同的版本。请查看传统的JSFiddle 进行测试。

简而言之,我采用了非侵入式修改Masonry的方式,以最优化的方式实现了预期的行为。

$(function() {

  var fillerHtml = '<div></div>',
    fillerClassName = 'filler',
    initialItemCount = null;

  function toggleFillers() {
    var masonry = $grid.data('masonry'),
      currentItemCount = masonry.items.length,
      items = masonry.items,
      cols = masonry.cols,
      expectedItemCount = 0,
      lastRowItemCount = 0,
      lastRowFillerCount = 0,
      fillersToRemove = [],
      fillersToAddCount = 0,
      fillersToAdd = [];

    if (initialItemCount === null) {
      initialItemCount = currentItemCount;
    }

    lastRowItemCount = initialItemCount % cols;
    lastRowFillerCount = (lastRowItemCount !== 0) ? cols - lastRowItemCount : 0;
    expectedItemCount = initialItemCount + lastRowFillerCount;
    
    $('.result').html('No: of lis in a row = ' + cols + '<br>' + 'No: of lis in last row = ' + lastRowItemCount);

    if (expectedItemCount !== currentItemCount) {
      if (currentItemCount > expectedItemCount) {
        var itemsToRemove = items.slice(initialItemCount + lastRowFillerCount);

        $.each(itemsToRemove, function(index, item) {
          fillersToRemove.push(item.element);
        });

        masonry.remove(fillersToRemove);
        masonry.layout();
      } else {
        fillersToAddCount = expectedItemCount - currentItemCount;
        fillerClassName = masonry.options.itemSelector.replace('.', '') + ' ' + fillerClassName;

        while (fillersToAddCount) {
          $el = $(fillerHtml).addClass(fillerClassName);
          $grid.append($el);
          fillersToAddCount = fillersToAddCount - 1;
        }

        masonry.reloadItems();
        masonry.layout();
      }
    }
  }

  var $grid = $('.grid');

  $grid.masonry({
    itemSelector: '.item',
    isFitWidth: true,
    gutter: 20
  });
  $grid.masonry('on', 'layoutComplete', toggleFillers);
  $grid.masonry('layout');
});
.grid {
  margin: 0 auto;
}
.item,
.filler {
  margin-bottom: 20px;
  border: 1px solid red;
  height: 80px;
  width: 80px;
}
.filler {
  background-color: #999;
  border: 1px solid blue;
}
<script type="text/javascript" src="//code.jquery.com/jquery-2.1.3.js"></script>
<link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<script type="text/javascript" src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/masonry/3.3.2/masonry.pkgd.min.js"></script>
<input type="hidden" name="hfTotalGridItems" id="hfTotalGridItems" value="10" />

<div class="grid">
  <div class="item">
    <div>lorem</div>
  </div>
  <div class="item">
    <div>lorem</div>
  </div>
  <div class="item">
    <div>lorem</div>
  </div>
  <div class="item">
    <div>lorem</div>
  </div>
  <div class="item">
    <div>lorem</div>
  </div>
  <div class="item">
    <div>lorem</div>
  </div>
  <div class="item">
    <div>lorem</div>
  </div>
  <div class="item">
    <div>lorem</div>
  </div>
  <div class="item">
    <div>lorem</div>
  </div>
  <div class="item">
    <div>lorem</div>
  </div>
</div>
<div class="result"></div>

我已经玩了一段时间的Masonry,所以我决定将其打包成插件,如果您想在其他地方使用它,可以使用bower安装或从GitHub获取源代码。

bower install jquery-masonry-autofill

这里有一个带插件演示的JSFiddle


这个完美地工作了,即使在砖石方面有不同的方法!感谢 @halfzebra!我喜欢你如何在github上创建了一个插件让每个人都可以使用。这对于想要相同功能的其他人非常有用。赞!@jjbskir仍然使用masonry的附加功能,成功实现了它。 - basagabi
1
@user1781041 感谢你的启发!我已经更新了repo,并添加了原始问题的链接。 - halfzebra

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接