如何制作平底同位素布局?

问题描述 投票:0回答:2

我正在使用同位素js https://isotope.metafizzy.co/并且无法理解如何使我的布局具有平底,如下所示https://diefinnhutte.qodeinteractive.com/masonry-portfolio/ 。 我无法为我的块设置固定高度,但在上面的示例中,我认为同位素给出了自己的高度。

如何制作?

我有简单的代码:

<div class="grid">
  <div class="grid-item">...</div>
  <div class="grid-item">...</div>
  <div class="grid-item">...</div>
  <div class="grid-item">...</div>
  <div class="grid-item">...</div>
  <div class="grid-item">...</div>
</div>

我的CSS:

.grid-item {width: 33%}

和js:

$('.grid').isotope({
    itemSelector: '.grid-item',
    columnWidth: '.grid-item',
    percentPosition: true,
});

在网格项内我有 img,它们的高度可以不同,那么我该怎么办?

提前致谢!

javascript jquery-isotope masonry
2个回答
0
投票

同位素非常适合创建这些布局,但它有一些怪癖。在您的情况下,您正在使用图像,这些图像可能决定布局的计算方式。我建议您使用同一作者的 imagesLoaded 库,首先检查图像是否已加载,然后渲染布局。否则,在加载图像之前,砌体布局中的项目将没有任何高度。

如果您想要顶部和底部平坦的布局,那么您将需要一些固定的高度值。如果图像的完整比例比高度更重要,那么这是不可能的。

您可以使用 CSS 中的

object-fit
属性为图像提供
background-size: cover
类型的效果。它将确保任何给定的图像将覆盖砌体网格中项目的整个空间。

在这些示例中,我使用了多个不同大小的图像,尽管存在差异,但它们都可以正常工作。

查看下面带有同位素和图像的片段。

var $grid = $('.grid').imagesLoaded( function() {
  $grid.isotope({
    itemSelector: '.grid-item',
    percentPosition: true,
    masonry: {
      columnWidth: '.grid-item',
    }
  });
});
*, *::before, *::after {
  box-sizing: border-box;
}

.grid-item {
  position: relative;
  display: grid;
  grid-template-columns: 1fr;
  grid-template-rows: 1fr;
  width: 33.3333333%;
  height: auto;
}

.grid-item.is-wide {
  width: 66.6666666%;
}

.grid-item::before {
  content: "";
  grid-area: 1 / 1 / 2 / 2;
  display: block;
}

.grid-item::before,
.grid-item.is-wide.is-high::before {
  padding-top: 100%;
}

.grid-item.is-wide::before {
  padding-top: 50%;
}


.grid-item.is-high::before {
  padding-top: 200%;
}

.grid-item img {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  padding: 5px;
  -o-object-fit: cover;
  object-fit: cover;
  z-index: 1;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://unpkg.com/imagesloaded@4/imagesloaded.pkgd.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.isotope/3.0.6/isotope.pkgd.min.js"></script>
<div class="grid">
  <div class="grid-item">
    <img src="https://www.fillmurray.com/640/360" alt="640x360"/>
  </div>
  <div class="grid-item is-wide">
    <img src="https://www.fillmurray.com/360/640" alt="360x640"/>
  </div>
  <div class="grid-item is-high">
    <img src="https://www.fillmurray.com/420/420" alt="420x420"/>
  </div>
  <div class="grid-item">
    <img src="https://www.fillmurray.com/640/360" alt="640x360"/>
  </div>
  <div class="grid-item ">
    <img src="https://www.fillmurray.com/640/800" alt="640x800"/>
  </div>
  <div class="grid-item is-wide">
    <img src="https://www.fillmurray.com/480/320" alt="640x360"/>
  </div>
  <div class="grid-item">
    <img src="https://www.fillmurray.com/640/360" alt="640x360"/>
  </div>
  <div class="grid-item">
    <img src="https://www.fillmurray.com/360/640" alt="360x640"/>
  </div>
  <div class="grid-item is-wide">
    <img src="https://www.fillmurray.com/420/420" alt="420x420"/>
  </div>
  <div class="grid-item is-high">
    <img src="https://www.fillmurray.com/640/360" alt="640x360"/>
  </div>
  <div class="grid-item">
    <img src="https://www.fillmurray.com/640/800" alt="640x800"/>
  </div>
  <div class="grid-item is-wide">
    <img src="https://www.fillmurray.com/480/320" alt="640x360"/>
  </div>
</div>


0
投票

您需要重写布局计算才能实现这一点。

现在,如果项目跨越多列,这可能会很复杂。但是,如果每个项目仅跨越一列,则相当容易做到。

逻辑:

  • 我们需要知道每个项目位于哪一列。默认情况下不存储此信息,因此我们以某种方式覆盖
    _getTopColPosition
    ,它的作用与以前相同,但我们为每个元素分配一个
    col
    属性,这样我们稍后就会知道它位于哪一列。
  • 当每个元素被分配到一列时,我们需要找出每一列的底部位置。这将是顶部 Y 坐标 + 每列中最后一项的高度。
  • 现在我们可以找到最高的一个和其余的了。我们将拉伸其余部分以匹配最高的部分。为此,我们计算高度差,将其除以项目数,并修改较短列中每个项目的 Y 位置和高度。
  • 我们让布局应用覆盖的位置和高度。
  • 我们还需要挂钩布局重置功能,否则元素将重新调整调整后的高度,导致它们随着每次重新布局而增长。

这是示例代码:

var elem = document.querySelector('.grid');
var isotope = new Isotope( elem, {
  // options
  itemSelector: '.grid-item',
  layoutMode: 'masonry' // Note: this solution only works with 'masonry' layout!
});

const layoutMode = isotope._mode()

const _getTopColPosition = layoutMode._getTopColPosition
layoutMode._getTopColPosition = function( colSpan, item ) {
  const result = _getTopColPosition.apply( layoutMode, arguments );
  item.col = result.col;
  return result;
};

const _getHorizontalColPosition = layoutMode._getHorizontalColPosition
layoutMode._getHorizontalColPosition = function( colSpan, item ) {
  const result = _getHorizontalColPosition.apply( layoutMode, arguments );
  item.col = result.col;
  return result;
};

const isotypeProto = Object.getPrototypeOf(isotope);
isotypeProto._processLayoutQueue = function( queue ) {

  equalizeProcessPositions(queue);

  this.updateStagger();
  queue.forEach( function( obj, i ) {
    isotypeProto._positionItem( obj.item, obj.x, obj.y, obj.isInstant, i );
  }, this );
}

function equalizeProcessPositions(queue) {
  // Each item has a col attribute. Sort them into an object where the col number is the key and each value is an array of items
  const entriesByCol = queue.reduce((acc, entry) => {
    if (!acc[entry.item.col]) {
      acc[entry.item.col] = [];
    }
    acc[entry.item.col].push(entry);
    return acc;
  }, {});

  const colYs = {};
  // Get maxY for each col, i.e. the y position and the height of the last item
  for (const [col, entry] of Object.entries(entriesByCol)) {
    const lastEntry = entriesByCol[col][entriesByCol[col].length - 1];
    colYs[col] = lastEntry.y + lastEntry.item.size.outerHeight;
  }

  const maxY = Math.max(...layoutMode.colYs);

  // Now adjust the items in each col
  for (const [col, colY] of Object.entries(colYs)) {
    if (colY !== maxY) {
      const diff = maxY - colY;
      const items = entriesByCol[col].length;
      const adjustment = diff / (items);

      // Loop each item in itemsByCol[i] and adjust the height and position
      for (const [i, entry] of Object.entries(entriesByCol[col])) {
        entry.item.size.innerHeight += adjustment;
        entry.item.size.outerHeight += adjustment;
        entry.item.size.height += adjustment;
        entry.item.element.style.height = entry.item.size.outerHeight + 'px';
        entry.y += i * adjustment;
      }
    }
  }
}


const _resetLayout = layoutMode._resetLayout
layoutMode._resetLayout = function() {
  this.items.forEach(item => {
    item.element.style.height = '';
  })
  return _resetLayout.apply( layoutMode, arguments );
};
© www.soinside.com 2019 - 2024. All rights reserved.