所有分类
  • 所有分类
  • Html5资源
  • React资源
  • Vue资源
  • Php资源
  • ‌小程序资源
  • Python资源

如何优雅的实现瀑布流布局Column、Grid

瀑布流布局是一种常见的网页排版方式,特别适合展示不规则内容(如图片、卡片等)。本文将详细介绍几种实现瀑布流的方案。

Column布局

优点:

  • 浏览器原生多列布局自动平衡各列高度,渲染性能好,减少JavaScript计算和内存占用
  • 无需手动计算元素放置位置
import { useState, useEffect } from "react";

export default function Home() {
  const [items, setItems] = useState([]);

  useEffect(() => {
    const generatedItems = Array.from({ length: 10 }, (_, index) => ({
      id: index + 1,
      height: Math.floor(Math.random() * 300) + 50, // 增大高度差异
      color: `hsl(${Math.random() * 360}, 70%, 80%)`,
    }));
    setItems(generatedItems);
  }, []);

  return (
    <div className="max-w-7xl mx-auto p-5">
      <h1 className="text-center text-2xl font-bold mb-8">瀑布流布局</h1>

      <div className="columns-2 gap-4 w-full md:columns-4 sm:columns-3">
        {items.map((item) => (
          <div
            key={item.id}
            className="break-inside-avoid mb-4 rounded-lg p-4 shadow-md flex justify-center items-center text-2xl font-bold text-gray-800 transition-transform hover:-translate-y-1 duration-300"
            style={{
              height: `${item.height}px`,
              backgroundColor: item.color,
            }}
          >
            {item.id}
          </div>
        ))}
      </div>
    </div>
  );
}

Grid 实现布局

核心实现策略:

  • 使用Grid布局创建固定数量的列:grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4
  • 在JavaScript中将数据预先分组到各列

布局优势:

  • 完全消除了空隙问题
  • 保持了水平方向的数据顺序
import { useState, useEffect } from "react";

export default function Home() {
  const [items, setItems] = useState([]);
  const columnCount = 4; // 定义列数

  useEffect(() => {
    // 生成测试数据
    const generatedItems = Array.from({ length: 60 }, (_, index) => ({
      id: index + 1,
      height: Math.floor(Math.random() * 200) + 100,
      color: `hsl(${Math.random() * 360}, 70%, 80%)`,
    }));
    setItems(generatedItems);
  }, []);

  // 将数据分组到不同的列中
  const columns = Array.from({ length: columnCount }, () => []);
  items.forEach((item, i) => {
    columns[i % columnCount].push(item);
  });

  return (
    <div className="max-w-7xl mx-auto p-5">
      <h1 className="text-center text-2xl font-bold mb-8">CSS3 瀑布流布局</h1>

      <div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4">
        {columns.map((column, columnIndex) => (
          <div key={columnIndex} className="flex flex-col gap-4">
            {column.map((item) => (
              <div
                key={item.id}
                className="w-full rounded-lg p-4 shadow-md flex justify-center items-center text-2xl font-bold text-gray-800 transition-transform hover:-translate-y-1 duration-300"
                style={{
                  height: `${item.height}px`,
                  backgroundColor: item.color,
                }}
              >
                {item.id}
              </div>
            ))}
          </div>
        ))}
      </div>
    </div>
  );
}

绝对定位

核心实现策略:

绝对定位机制

  • 使用position: absolute精确控制每个元素位置
  • 通过transform: translate(x, y)实现像素级精确定位
  • 避免了传统网格或弹性布局可能产生的空隙问题

最短列优先算法

const minHeightCol = columnHeights.current.indexOf(Math.min(...columnHeights.current));
  • 每个新元素总是放置在当前高度最低的列中
  • 动态跟踪和更新每列的累积高度
  • 确保所有列的高度尽可能接近,布局平衡

动态计算布局参数

  • 根据容器实际宽度动态计算列宽
  • 响应式调整列数:大屏4列、中屏3列、小屏2列
  • 精确计算元素放置坐标,避免四舍五入误差

布局重绘响应机制

  • 监听窗口resize事件自动触发重新计算
  • 在窗口大小变化时重新分配所有元素位置
  • 保持容器高度与内容高度同步

布局优势

无空隙视觉效果

  • 完全消除了传统CSS Grid或Flexbox布局中常见的空隙问题
  • 元素紧密排列,最大化利用可用空间

高度动态平衡

  • 自动调整元素位置以保持各列高度平衡
  • 即使部分元素高度差异较大时仍能保持整体布局协调

性能优化

  • 使用CSS transform属性进行定位,利用GPU加速
  • 通过useRef避免不必要的重渲染
  • 只在必要时(窗口大小变化、数据更新)重新计算布局

适应性强

  • 自动适应不同屏幕尺寸和方向
  • 支持动态添加和移除元素
  • 适用于各种内容类型和不规则高度的元素
import { useState, useEffect, useRef } from "react";

export default function Home() {
  const [items, setItems] = useState([]);
  const [layout, setLayout] = useState([]);
  const containerRef = useRef(null);
  const columns = useRef(0);
  const columnWidth = useRef(0);
  const columnHeights = useRef([]);

  // 生成测试数据
  useEffect(() => {
    const generatedItems = Array.from({ length: 10 }, (_, index) => ({
      id: index + 1,
      height: Math.floor(Math.random() * 200) + 100,
      color: `hsl(${Math.random() * 360}, 70%, 80%)`,
    }));
    setItems(generatedItems);
  }, []);

  // 计算瀑布流布局
  useEffect(() => {
    if (!items.length || !containerRef.current) return;

    const updateLayout = () => {
      // 获取容器宽度
      const containerWidth = containerRef.current.clientWidth;
      const gap = 16; // 间隙大小

      // 计算列数和列宽
      let colCount;
      if (window.innerWidth >= 1024) {
        colCount = 4; // 大屏幕
      } else if (window.innerWidth >= 768) {
        colCount = 3; // 中屏幕
      } else {
        colCount = 2; // 小屏幕
      }

      const colWidth = (containerWidth - (colCount - 1) * gap) / colCount;

      columns.current = colCount;
      columnWidth.current = colWidth;
      columnHeights.current = Array(colCount).fill(0); // 初始化列高度

      // 计算每个项目的位置
      const newLayout = items.map((item) => {
        // 找出高度最小的列
        const minHeightCol = columnHeights.current.indexOf(
          Math.min(...columnHeights.current)
        );

        // 计算x和y坐标
        const x = minHeightCol * (colWidth + gap);
        const y = columnHeights.current[minHeightCol];

        // 更新该列高度
        columnHeights.current[minHeightCol] += item.height + gap;

        // 返回带位置信息的项目
        return {
          ...item,
          x,
          y,
        };
      });

      setLayout(newLayout);
    };

    // 初始计算
    updateLayout();

    // 监听窗口大小变化
    window.addEventListener("resize", updateLayout);
    return () => window.removeEventListener("resize", updateLayout);
  }, [items]);

  return (
    <div className="max-w-7xl mx-auto p-5">
      <h1 className="text-center text-2xl font-bold mb-8">瀑布流布局</h1>

      <div
        ref={containerRef}
        className="relative w-full"
        style={{
          height: `${Math.max(...columnHeights.current, 100)}px`,
        }}
      >
        {layout.map((item) => (
          <div
            key={item.id}
            className="absolute rounded-lg p-4 shadow-md flex justify-center items-center text-2xl font-bold text-gray-800 transition-all duration-300 hover:-translate-y-1"
            style={{
              width: `${columnWidth.current}px`,
              height: `${item.height}px`,
              backgroundColor: item.color,
              transform: `translate(${item.x}px, ${item.y}px)`,
            }}
          >
            {item.id}
          </div>
        ))}
      </div>
    </div>
  );
}

资源下载
下载价格免费
注意:本网站资源属于虚拟产品,不支持退款。请谨慎购买! 购买后资源无法下载,请联系客服QQ:844475003,微信号:th844475003。
原文链接:https://code.ifrontend.net/archives/608,转载请注明出处。
0

评论0

显示验证码
没有账号?注册  忘记密码?