使用js写一个简单的【瀑布流】布局效果

效果:


  • 瀑布流布局(Masonry Layout)是一种常见的网页布局方式,尤其适用于展示图片、卡片等内容。这种布局方式有以下特点:

  1. 不规则排列:瀑布流布局允许元素高度不一,使得每个元素可以根据其内容自适应高度。

  2. 高效利用空间:通过将新元素放置在当前高度最小的列中,瀑布流布局能够最大化地利用页面的垂直空间,减少空白区域,让页面看起来更加紧凑和美观。

  3. 动态加载:瀑布流布局通常与无限滚动(Infinite Scroll)或懒加载(Lazy Loading)结合使用,以便在用户滚动页面时动态加载更多内容,提高用户体验和页面加载速度。

  4. 响应式设计:瀑布流布局可以根据屏幕大小和设备类型进行调整,确保在不同设备上都有良好的显示效果。例如,可以根据屏幕宽度动态调整列数或元素大小。

  5. 视觉一致性:尽管元素高度不一,但瀑布流布局通过精确的排列和对齐,使得页面整体看起来整齐有序,具有较好的视觉一致性。

  6. 流畅的用户体验:使用瀑布流布局可以让用户在浏览内容时有一种连续流动的感觉,特别适合用于图片库、博客文章列表、商品展示等需要大量内容展示的场景。

  7. 复杂性管理:实现瀑布流布局需要处理元素的绝对定位和动态计算,因此相对于简单的网格布局来说,技术实现稍显复杂,需要结合 JavaScript 来动态调整元素位置。

这些特点使得瀑布流布局成为一种非常灵活和实用的网页布局方式,特别适合展示大量内容并且希望保持页面整洁和美观的场景。 那怎样利用js实现上述的布局呢?

实现瀑布流布局

我们如何实现类似于花瓣网的瀑布流布局呢?我们先从花瓣网上下些图片,作为素材。

我们看下,如果我们只是利用简单的排列布局:


.item {
  display: inline - block;
  margin-bottom: 10px; /* 底部间距 */
  border: 1px solid #ccc;
}

<div id="waterfall-container">
  <div class="item">
    <img src="./images/1.webp" alt="" />
  </div>
  <div class="item">
    <img src="./images/2.webp" alt="" />
  </div>
  <div class="item">
    <img src="./images/3.webp" alt="" />
  </div>
  <div class="item">
    <img src="./images/4.webp" alt="" />
  </div>
  <div class="item">
    <img src="./images/5.webp" alt="" />
  </div>
  <div class="item">
    <img src="./images/6.webp" alt="" />
  </div>
  <div class="item">
    <img src="./images/7.webp" alt="" />
  </div>
  <div class="item">
    <img src="./images/8.webp" alt="" />
  </div>
  <div class="item">
    <img src="./images/9.webp" alt="" />
  </div>
  <!-- 更多项目 -->
</div>

很显然这样不是很美观,而且页面空间没有得到进一步的利用。

那怎样实现瀑布流布局呢?

实现瀑布流布局的步骤如下:

1、获取父元素总宽度和图片宽度,确定第一行要展示的图片个数 n

    • 计算父元素总宽度和图片宽度,然后根据父元素宽度和图片宽度计算出第一行要展示的图片个数 n,这里存在不整除的问题,我们可以向下取整。

    • 重置父元素总宽度为 n * imgWidth,然后设置父元素居中,并为图片元素设置 padding: 5px 避免图片之间展示拥挤。

    • 使用一个长度为 n 的数组,来存储第一行各个图片的高度。

2、从第 n + 1 张图片开始,找到高度数组中最小的元素索引 index,利用绝对定位放置图片,并同步更新该索引对应的高度:

  • 遍历从第 n + 1 张图片开始的所有图片,找到高度数组中最小值对应的索引 index

  • 将该图片绝对定位放置在父元素中,top 值为高度数组中索引为 index 的高度数据,left 值为 index * 图片宽度

  • 更新高度数组中索引为 index 的值,加上该图片的高度。

3、更新高度数组中索引为 index 的值,加上该图片的高度。

js代码实现: 


function calculateColumns() {
  const container = document.getElementById('waterfall-container');
  // Reset the width to auto to get the natural width of the container
  container.style.width = 'auto';
  const items = container.getElementsByClassName('item');
  const parentWidth = container.clientWidth;
  const itemWidth = items[0].offsetWidth + 10; // 10px for padding (5px on each side)
  const n = Math.floor(parentWidth / itemWidth);
  
  return { container, items, parentWidth, itemWidth, n };
}

function resetContainerWidth(container, n, itemWidth) {
  container.style.width = n * itemWidth + 'px';
  container.style.margin = '0 auto';
}

function positionItems(items, n, itemWidth) {
  // Array to store heights of each column
  const columnHeights = new Array(n).fill(0);

  // Position each item
  Array.from(items).forEach((item, i) => {
    if (i < n) {
      // First row items
      item.style.top = '0px';
      item.style.left = (i * itemWidth) + 'px';
      columnHeights[i] = item.offsetHeight + 10; // Initial height with padding
    } else {
      // Find the shortest column
      const minColIndex = columnHeights.indexOf(Math.min(...columnHeights));
      item.style.top = columnHeights[minColIndex] + 'px';
      item.style.left = (minColIndex * itemWidth) + 'px';
      columnHeights[minColIndex] += item.offsetHeight + 10; // Update column height
    }
  });
}

function waterfallLayout() {
  const { container, items, parentWidth, itemWidth, n } = calculateColumns();
  resetContainerWidth(container, n, itemWidth);
  positionItems(items, n, itemWidth);
}

// Initial layout
window.onload = waterfallLayout;

// Recalculate layout on window resize
window.onresize = waterfallLayout;

代码解读

  1. 函数 calculateColumns

    • 获取 waterfall-container 容器和其中的所有项目。

    • 先将容器宽度重置为 auto,以便页面尺寸变化后能够获取到其自然宽度。

    • 获取父容器的宽度,并计算项目的宽度(包括 padding)。

    • 计算每行能容纳的项目个数 n

  2. 函数 resetContainerWidth

    • 根据项目个数 n 和项目宽度 itemWidth 重置父元素的宽度,使其居中。

  3. 函数 positionItems

    • 创建一个数组 columnHeights 来存储每列的高度。

    • 遍历所有项目,第一行的项目直接放置在第一行,其余项目找到高度最小的列进行放置,并更新该列的高度。

  4. 函数 waterfallLayout

    • 调用 calculateColumns 获取必要的布局参数。

    • 调用 resetContainerWidth 重置父元素的宽度。

    • 调用 positionItems 重新布局所有项目。

  5. 事件监听:

    • 在 window.onload 事件中调用 waterfallLayout 初始化布局。

    • 在 window.onresize 事件中调用 waterfallLayout,确保在窗口大小变化时重新计算布局。

通过上述步骤和代码,确保每次页面尺寸变化时都能正确获取最新的父容器宽度,并重新计算和调整瀑布流布局。

css代码


#waterfall-container {
    position: relative;
    margin: 0 auto;
  }

  #waterfall-container .item {
    position: absolute;
    padding: 5px;
    box-sizing: border-box;
  }

页面尺寸变化

猜你喜欢

转载自blog.csdn.net/YN2000609/article/details/142459737