跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
HTML / CSS大前端算法

前端瀑布流布局:从基础实现到高性能优化全解析

前端瀑布流布局原理与实现。核心基于多列动态高度计算与绝对定位,通过原生 JS 实现基础渲染、响应式适配及无限滚动加载。针对图片异步加载导致的布局错乱、DOM 节点过多卡顿等高频问题提供解决方案。同时介绍 Vue3 和 React 框架下的第三方库实战方案,并总结生产环境下的图片懒加载、防抖节流、虚拟滚动等性能优化策略,帮助开发者构建高性能瀑布流页面。

观心发布于 2026/4/6更新于 2026/10/22113 浏览
前端瀑布流布局:从基础实现到高性能优化全解析

前端瀑布流布局:从基础实现到高性能优化全解析

瀑布流(Waterfall Layout)是前端开发中极具代表性的流式布局方案,以非固定高度、多列自适应、内容错落有致的特点成为图片展示、商品列表、内容资讯等场景的主流选择(如 Pinterest、花瓣网、小红书首页等)。其核心逻辑是让元素按自身高度自适应填充到页面空白区域,打破传统网格布局的固定行列限制,兼顾视觉美感与空间利用率。本文将从瀑布流的核心原理出发,依次讲解原生 JS 基础实现、响应式适配、高频问题解决方案及生产环境高性能优化方案,同时补充主流框架(Vue/React)的实战技巧。

一、瀑布流核心原理与适用场景

1. 核心设计原理

瀑布流的本质是'多列布局 + 动态高度计算 + 元素精准定位',核心步骤可概括为 3 点:

  1. 确定页面展示列数(根据设备宽度、设计稿要求动态调整);
  2. 计算每一列的当前累计高度,找到高度最小的列;
  3. 将下一个元素定位到该最小高度列的顶部,同时更新该列的累计高度。

整个过程类似'往多个不同高度的杯子里倒水,每次都倒到当前最浅的杯子中',最终实现所有列高度尽可能接近,页面无大面积空白。

2. 核心优势

  • 适配非等宽等高元素:完美支持图片、卡片等高度不统一的内容展示,避免传统网格布局的大量留白;
  • 视觉层次丰富:错落的布局形式更吸引用户注意力,提升内容浏览体验;
  • 空间利用率高:最大化利用页面可视区域,适合海量内容的无限加载场景;
  • 响应式友好:可通过动态调整列数适配移动端、平板、PC 等不同设备。

3. 典型适用场景

  • 图片 / 素材展示平台(花瓣网、站酷);
  • 电商商品列表(非标品、多规格商品);
  • 内容资讯平台(图文混合、不同长度的文章卡片);
  • 短视频 / 直播封面列表(封面尺寸不统一场景);

注意:若需展示的元素高度统一,或要求严格的行列对齐(如表格、商品网格),则不建议使用瀑布流。

二、前置知识:实现瀑布流的核心 CSS/JS 基础

在动手实现前,先掌握 2 个核心基础知识点,避免开发中踩坑:

1. CSS 基础:定位与盒模型

瀑布流的元素定位主要依赖绝对定位(position: absolute),父容器需设置相对定位(position: relative)作为定位参考;同时需重置元素默认盒模型,避免边距、内边距影响宽度计算:

/* 瀑布流父容器:相对定位 + 清除默认边距 */
.waterfall {
  position: relative;
  width: 100%;
  margin: 0 auto;
  box-sizing: border-box;
}

/* 瀑布流子元素:绝对定位 + 固定宽度 + 盒模型重置 */
.waterfall-item {
  position: absolute;
  width: calc(100% / 4 - 20px); /* 4 列布局,间距 20px */
  box-sizing: border-box;
  margin-bottom: ; 
}

目录

  1. 前端瀑布流布局:从基础实现到高性能优化全解析
  2. 一、瀑布流核心原理与适用场景
  3. 1. 核心设计原理
  4. 2. 核心优势
  5. 3. 典型适用场景
  6. 二、前置知识:实现瀑布流的核心 CSS/JS 基础
  7. 1. CSS 基础:定位与盒模型
  8. 2. JS 基础:核心 API 与计算逻辑
  9. 三、原生 JS 实现基础瀑布流(核心版)
  10. 1. 完整代码实现
  11. 2. 核心逻辑拆解
  12. 四、必做优化 1:响应式瀑布流(适配所有设备)
  13. 1. 响应式核心优化代码
  14. 2. 响应式优化亮点
  15. 五、必做优化 2:无限滚动加载(海量内容适配)
  16. 1. 无限滚动核心实现代码
  17. 2. 无限滚动优化亮点
  18. 六、高频问题解决方案(开发必看,避坑指南)
  19. 问题 1:图片加载慢导致元素高度计算错误,布局错乱
  20. 问题 2:无限滚动导致 DOM 节点过多,页面卡顿
  21. 问题 3:绝对定位导致元素无法参与正常文档流
  22. 问题 4:移动端滚动穿透
  23. 七、框架实战:Vue3/React 瀑布流快速实现
  24. 1. Vue3 瀑布流实战(推荐:vue3-waterfall-plugin)
  25. 八、生产环境高性能优化终极指南
  26. 1. 图片优化(优先级★★★★★)
  27. 2. 防抖 / 节流优化(优先级★★★★★)
  28. 3. 虚拟滚动(优先级★★★★☆)
  29. 4. 接口请求优化(优先级★★★★☆)
  30. 5. 重绘 / 重排优化(优先级★★★☆☆)
  31. 6. 移动端专属优化(优先级★★★☆☆)
  32. 九、总结
20px
/* 元素上下间距 */

2. JS 基础:核心 API 与计算逻辑

  • 元素尺寸计算:offsetWidth/offsetHeight(获取元素实际宽高,包含边框、内边距);
  • 样式设置:style.left/style.top(设置绝对定位元素的位置);
  • 窗口监听:window.addEventListener('resize', …)(监听窗口大小变化,实现响应式);
  • 滚动监听:window.addEventListener('scroll', …)(实现无限加载)。

三、原生 JS 实现基础瀑布流(核心版)

本章节实现固定列数、静态数据、一次性渲染的基础瀑布流,是所有进阶方案的核心基础,代码无框架依赖、可直接运行,适合理解底层逻辑。

1. 完整代码实现

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>原生 JS 基础瀑布流</title>
<style>
* { margin: 0; padding: 0; list-style: none; }
.waterfall { position: relative; width: 1200px; margin: 0 auto; }
.waterfall-item { position: absolute; width: calc(100% / 4 - 15px); border-radius: 8px; overflow: hidden; box-shadow: 0 2px 8px rgba(0,0,0,0.1); }
.waterfall-item img { width: 100%; display: block; } /* 清除图片底部空白 */
.waterfall-item p { padding: 10px; font-size: 14px; color: #333; }
</style>
</head>
<body>
<div class="waterfall" id="waterfall"></div>
<script>
// 1. 模拟接口返回的静态数据(图片高度随机,模拟非等高场景)
const waterfallData = Array.from({ length: 20 }, (_, index) => ({
  id: index + 1,
  imgUrl: `https://picsum.photos/300/${200 + Math.floor(Math.random() * 300)}`,
  title: `瀑布流卡片${index + 1}`
}));

// 2. 瀑布流核心配置
const config = {
  column: 4, // 固定 4 列布局
  gap: 15, // 列之间、元素之间的间距(px)
  container: document.getElementById('waterfall')
};

// 3. 初始化瀑布流
initWaterfall(waterfallData);

/**
 * 瀑布流核心渲染函数
 * @param {Array} data - 渲染数据
 */
function initWaterfall(data) {
  if (!data.length || !config.container) return;
  
  // 每列的宽度 =(容器宽度 - (列数 -1)*间距) / 列数
  const containerWidth = config.container.offsetWidth;
  const itemWidth = (containerWidth - (config.column - 1) * config.) / config.;
  
  
   columnHeights =  (config.).();
  
  
  data.( {
     itemEl = .();
    itemEl. = ;
    itemEl. = ;
    config..(itemEl);
    
    
    itemEl.. = ;
    
    
     minIndex = columnHeights.(.(...columnHeights));
    
    
     left = minIndex * (itemWidth + config.);
     top = columnHeights[minIndex];
    
    
    itemEl.. = ;
    itemEl.. = ;
    
    
    columnHeights[minIndex] = top + itemEl. + config.;
  });
  
  
  config... = ;
}
</script>
</body>
</html>

2. 核心逻辑拆解

以上代码是瀑布流的最核心实现,关键步骤已标注注释,核心亮点总结:

  1. 动态计算元素宽度:根据容器宽度、列数、间距自动计算,避免硬编码;
  2. 列高度数组管理:用 columnHeights 数组存储每列的累计高度,初始值为 0,每次渲染后更新;
  3. 最小高度列定位:通过 Math.min(…columnHeights) 找到最矮列,再用 indexOf 获取其索引,确保元素始终填充空白区域;
  4. 解决父容器塌陷:渲染完成后,将父容器高度设置为最高列的高度,避免页面布局混乱;
  5. 无框架依赖:纯原生 CSS+JS 实现,可直接嵌入任意前端项目。

四、必做优化 1:响应式瀑布流(适配所有设备)

基础版为固定列数,在移动端、平板等设备上会出现布局错乱,响应式适配是瀑布流的必备优化,核心思路是根据窗口宽度动态调整列数,结合「窗口大小监听 + 重新渲染」实现。

1. 响应式核心优化代码

在基础版代码基础上,新增 / 修改以下代码(关键优化部分标注注释):

// 1. 修改配置:将固定列数改为根据宽度匹配的列数规则
const config = {
  gap: 15,
  container: document.getElementById('waterfall'),
  // 响应式列数规则:[最小宽度,对应列数],按从大到小排序
  columnRules: [
    [1200, 4], // 宽度≥1200px:4 列
    [992, 3],  // 992px≤宽度<1200px:3 列
    [768, 2],  // 768px≤宽度<992px:2 列
    [0, 1]     // 宽度<768px:1 列(移动端)
  ]
};

// 2. 新增:根据窗口宽度获取当前应显示的列数
function getCurrentColumn() {
  const windowWidth = document.documentElement.clientWidth;
  const { columnRules } = config;
  for (const [minWidth, column] of columnRules) {
    if (windowWidth >= minWidth) return column;
  }
  return 1; // 兜底:默认 1 列
}

// 3. 改造初始化函数:支持动态列数,抽离重置逻辑
function initWaterfall(data) {
  if (!data.length || !config.container) return;
  
  // 重置容器:清空原有内容、清除原有高度、重置列高度数组
  config.container.innerHTML = '';
  config.container.style.height = 'auto';
  
  const containerWidth = config.container.offsetWidth;
  const column = getCurrentColumn();
  const itemWidth = (containerWidth - (column - 1) * config.gap) / column;
  const columnHeights = new Array(column).fill(0);
  
  data.forEach(item => {
    const itemEl = document.createElement('div');
    itemEl.className = 'waterfall-item';
    itemEl.innerHTML = `<img src="${item.imgUrl}" alt="${item.title}"><p>${item.title}</p>`;
    config.container.appendChild(itemEl);
    
    itemEl.style.width = `${itemWidth}px`;
    const minIndex = columnHeights.indexOf(Math.min(...columnHeights));
    const left = minIndex * (itemWidth + config.gap);
    const top = columnHeights[minIndex];
    
    itemEl.style.left = `${left}px`;
    itemEl.style.top = `${top}px`;
    columnHeights[minIndex] = top + itemEl.offsetHeight + config.gap;
  });
  
  config.container.style.height = `${Math.max(...columnHeights) - config.gap}px`;
}

// 4. 新增:窗口大小变化监听(添加防抖,避免频繁渲染)
let resizeTimer = null;
window.addEventListener('resize', () => {
  clearTimeout(resizeTimer);
  resizeTimer = setTimeout(() => {
    initWaterfall(waterfallData);
  }, 50);
});

initWaterfall(waterfallData);

2. 响应式优化亮点

  1. 灵活的列数规则:通过 columnRules 配置不同宽度区间的列数,支持按需扩展,适配所有设备;
  2. 重置逻辑完善:重新渲染前清空容器内容、重置高度,避免新旧元素重叠;
  3. 防抖优化:窗口大小变化时添加 50ms 防抖,避免频繁触发渲染,提升性能;
  4. 动态高度数组:根据当前列数重新初始化 columnHeights 数组,确保布局正确。

五、必做优化 2:无限滚动加载(海量内容适配)

瀑布流常用于海量内容展示,一次性渲染所有数据会导致首屏加载慢、DOM 节点过多、页面卡顿,无限滚动加载是解决该问题的核心方案,核心思路是:首屏只渲染部分数据,当用户滚动到页面底部时,异步加载下一页数据并追加到瀑布流中。

1. 无限滚动核心实现代码

结合响应式瀑布流,新增无限滚动逻辑(关键部分标注注释):

// 1. 新增全局状态:管理分页、加载状态
const state = {
  page: 1,
  pageSize: 10,
  isLoading: false,
  hasMore: true
};

// 2. 模拟异步接口请求:获取瀑布流数据
async function fetchWaterfallData(page, pageSize) {
  await new Promise(resolve => setTimeout(resolve, 500));
  const total = 30;
  const start = (page - 1) * pageSize;
  const end = start + pageSize;
  if (start >= total) return [];
  return Array.from({ length: Math.min(pageSize, total - start) }, (_, index) => ({
    id: start + index + 1,
    imgUrl: `https://picsum.photos/300/${200 + Math.floor(Math.random() * 300)}`,
    title: `瀑布流卡片${start + index + 1}`
  }));
}

// 3. 改造渲染函数:新增追加渲染模式
function renderWaterfall(data, isAppend = false) {
  const container = config.container;
  if (!data.length || !container) return;
  
  const containerWidth = container.offsetWidth;
  const column = getCurrentColumn();
  const itemWidth = (containerWidth - (column - 1) * config.gap) / column;
  
  let columnHeights = isAppend ? JSON.parse(localStorage.getItem('columnHeights')) || new Array(column).fill(0) : new Array(column).fill(0);
  
  if (!isAppend) {
    container.innerHTML = '';
    container.style.height = 'auto';
  }
  
  data.forEach(item => {
    const itemEl = document.createElement('div');
    itemEl.className = 'waterfall-item';
    itemEl.innerHTML = `<img src="${item.imgUrl}" alt="${item.title}"><p>${item.title}</p>`;
    container.appendChild(itemEl);
    
    itemEl.style.width = `${itemWidth}px`;
    const minIndex = columnHeights.indexOf(Math.min(...columnHeights));
    const left = minIndex * (itemWidth + config.gap);
    const top = columnHeights[minIndex];
    
    itemEl.style.left = `${left}px`;
    itemEl.style.top = `${top}px`;
    columnHeights[minIndex] = top + itemEl.offsetHeight + config.gap;
  });
  
  container.style.height = `${Math.max(...columnHeights) - config.gap}px`;
  localStorage.setItem('columnHeights', JSON.stringify(columnHeights));
}

// 4. 新增:首屏加载函数
async function loadFirstScreen() {
  state.isLoading = true;
  const data = await fetchWaterfallData(state.page, state.pageSize);
  state.hasMore = data.length === state.pageSize;
  renderWaterfall(data, false);
  state.isLoading = false;
}

// 5. 新增:加载下一页函数
async function loadNextPage() {
  if (state.isLoading || !state.hasMore) return;
  state.isLoading = true;
  state.page++;
  const data = await fetchWaterfallData(state.page, state.pageSize);
  state.hasMore = data.length === state.pageSize;
  renderWaterfall(data, true);
  state.isLoading = false;
}

// 6. 新增:滚动监听,实现无限加载
function handleScroll() {
  const scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
  const clientHeight = document.documentElement.clientHeight;
  const scrollHeight = document.documentElement.scrollHeight;
  if (scrollTop + clientHeight >= scrollHeight - 200) {
    loadNextPage();
  }
}
window.addEventListener('scroll', handleScroll);

// 7. 窗口大小变化时,重新加载首屏
let resizeTimer = null;
window.addEventListener('resize', () => {
  clearTimeout(resizeTimer);
  resizeTimer = setTimeout(() => {
    state.page = 1;
    state.hasMore = true;
    loadFirstScreen();
  }, 50);
});

loadFirstScreen();

2. 无限滚动优化亮点

  1. 防重复请求:通过 isLoading 状态控制,避免滚动时多次触发接口请求;
  2. 追加渲染模式:新增 isAppend 参数,区别全量渲染和追加渲染,复用原有列高度数组;
  3. 列高度持久化:通过 localStorage 存储当前列高度数组,确保追加渲染时元素定位准确;
  4. 提前加载:滚动到距离底部 200px 时触发加载,减少用户等待时间;
  5. 状态管理:通过 state 对象统一管理页码、每页数量、加载状态;
  6. 响应式兼容:窗口大小变化时重置状态并重新加载首屏。

六、高频问题解决方案(开发必看,避坑指南)

问题 1:图片加载慢导致元素高度计算错误,布局错乱

原因:图片异步加载,未加载完成时 offsetHeight 获取的是初始高度。 解决方案:图片加载完成后再渲染 / 更新高度。

data.forEach(item => {
  const itemEl = document.createElement('div');
  itemEl.className = 'waterfall-item';
  itemEl.innerHTML = `<img src="${item.imgUrl}" alt="${item.title}" style="display: none;"><p>${item.title}</p>`;
  config.container.appendChild(itemEl);
  itemEl.style.width = `${itemWidth}px`;
  
  const img = itemEl.querySelector('img');
  img.onload = function() {
    img.style.display = 'block';
    const minIndex = columnHeights.indexOf(Math.min(...columnHeights));
    const left = minIndex * (itemWidth + config.gap);
    const top = columnHeights[minIndex];
    itemEl.style.left = `${left}px`;
    itemEl.style.top = `${top}px`;
    columnHeights[minIndex] = top + itemEl.offsetHeight + config.gap;
    config.container.style.height = `${Math.max(...columnHeights) - config.gap}px`;
    localStorage.setItem('columnHeights', JSON.stringify(columnHeights));
  };
  img.onerror = function() {
    img.src = '默认图片地址.png';
    img.onload();
  };
});

问题 2:无限滚动导致 DOM 节点过多,页面卡顿

解决方案:虚拟滚动(只渲染可视区域内的元素)。 对于海量内容的瀑布流,虚拟滚动是最优解。推荐直接使用成熟的第三方库:

  • 原生 / Vue2:vue-waterfall-easy
  • Vue3:@vueuse/core 的 useVirtualList
  • React:react-virtualized 的 Masonry 组件

问题 3:绝对定位导致元素无法参与正常文档流

解决方案:

  1. 设置父容器高度:渲染完成后将父容器高度设置为最高列的高度;
  2. 使用弹性布局兜底:给瀑布流容器添加 min-height,后续元素设置 clear: both。

问题 4:移动端滚动穿透

解决方案:禁止背景滚动。

function stopBodyScroll() {
  document.body.style.overflow = 'hidden';
  document.body.style.touchAction = 'none';
}
function resumeBodyScroll() {
  document.body.style.overflow = 'auto';
  document.body.style.touchAction = 'auto';
}

七、框架实战:Vue3/React 瀑布流快速实现

1. Vue3 瀑布流实战(推荐:vue3-waterfall-plugin)

步骤 1:安装依赖

npm install vue3-waterfall-plugin --save

步骤 2:全局注册组件

import { createApp } from 'vue';
import App from './App.vue';
import Vue3Waterfall from 'vue3-waterfall-plugin';
import 'vue3-waterfall-plugin/dist/style.css';

const app = createApp(App);
app.use(Vue3Waterfall);
app.mount('#app');

步骤 3:组件中使用

<template>
  <div class="waterfall-container">
    <vue3-waterfall :list="waterfallList" :gap="15" :column="column" @scrollReachBottom="loadNextPage">
      <template #default="{ item }">
        <div class="waterfall-item">
          <img v-lazy="item.imgUrl" alt="item.title" />
          <p>{{ item.title }}</p>
        </div>
      </template>
      <template #loading><div class="loading">加载中...</div></template>
      <template #noMore><div class="no-more">没有更多内容了</div></template>
    </vue3-waterfall>
  </div>
</template>
<script setup>
import { ref, onMounted, onResize } from 'vue';
import { vLazy } from 'vue3-lazy';

const column = ref(4);
const waterfallList = ref([]);
const page = ref(1);
const pageSize = ref(10);
const isLoading = ref(false);
const hasMore = ref(true);

const setColumn = () => {
  const width = document.documentElement.clientWidth;
  if (width >= 1200) column.value = 4;
  else if (width >= 992) column.value = 3;
  else if (width >= 768) column.value = 2;
  else column.value = 1;
};

const fetchData = async (page, pageSize) => {
  await new Promise(resolve => setTimeout(resolve, 500));
  const total = 30;
  const start = (page - 1) * pageSize;
  if (start >= total) return [];
  return Array.from({ length: Math.min(pageSize, total - start) }, (_, i) => ({
    id: start + i + 1,
    imgUrl: `https://picsum.photos/300/${200 + Math.floor(Math.random() * 300)}`,
    title: `Vue3 瀑布流${start + i + 1}`
  }));
};

const loadFirstScreen = async () => {
  isLoading.value = true;
  const data = await fetchData(page.value, pageSize.value);
  waterfallList.value = data;
  hasMore.value = data.length === pageSize.value;
  isLoading.value = false;
};

const loadNextPage = async () => {
  if (isLoading.value || !hasMore.value) return;
  isLoading.value = true;
  page.value++;
  const data = await fetchData(page.value, pageSize.value);
  waterfallList.value.push(...data);
  hasMore.value = data.length === pageSize.value;
  isLoading.value = false;
};

onMounted(() => {
  setColumn();
  loadFirstScreen();
});
onResize(() => {
  setColumn();
});
</script>
<style scoped>
.waterfall-container { width: 1200px; margin: 0 auto; }
.waterfall-item { border-radius: 8px; overflow: hidden; box-shadow: 0 2px 8px rgba(0,0,0,0.1); }
.waterfall-item img { width: 100%; display: block; }
.waterfall-item p { padding: 10px; font-size: 14px; color: #333; }
.loading, .no-more { text-align: center; padding: 20px; font-size: 14px; color: #999; }
</style>

八、生产环境高性能优化终极指南

1. 图片优化(优先级★★★★★)

  1. 图片懒加载:使用 vue3-lazy、react-lazyload 或原生 loading="lazy";
  2. 图片压缩:推荐使用 WebP/AVIF 格式;
  3. 响应式图片:使用 srcset 和 sizes 属性;
  4. 设置图片宽高比:提前给图片容器设置宽高比,避免布局跳动。
.img-container { aspect-ratio: 3/4; overflow: hidden; }
.img-container img { width: 100%; height: 100%; object-fit: cover; }

2. 防抖 / 节流优化(优先级★★★★★)

  • 窗口 resize:防抖 50-100ms;
  • 滚动 scroll:节流 100-200ms,或防抖 50ms。

3. 虚拟滚动(优先级★★★★☆)

对于海量内容(超过 100 条)的瀑布流,虚拟滚动是解决 DOM 节点过多的最优解。

4. 接口请求优化(优先级★★★★☆)

  • 分页请求:按页加载数据;
  • 防重复请求:通过 isLoading 状态控制;
  • 数据缓存:对已加载的页面数据进行缓存;
  • 预加载:提前加载下一页数据。

5. 重绘 / 重排优化(优先级★★★☆☆)

  • 批量操作 DOM:尽量批量创建元素后再一次性插入 DOM;
  • 使用 CSS3 属性:避免使用 top/left 频繁修改元素位置,可结合 transform: translate();
  • 减少样式计算:给瀑布流元素添加固定的 width。

6. 移动端专属优化(优先级★★★☆☆)

  • 禁止滚动穿透;
  • 优化触摸事件:使用 touchmove 替代 scroll 事件;
  • 减少阴影 / 渐变;
  • 适配刘海屏 / 底部安全区:使用 env(safe-area-inset-top/bottom)。

九、总结

瀑布流布局是前端开发中兼具实用性与视觉美感的经典方案,其核心是围绕'动态列高度计算 + 元素精准定位'展开。学习路径包括:掌握原生基础实现、完成必备优化(响应式 + 无限滚动)、解决高频问题、框架实战以及生产环境优化(图片、防抖、虚拟滚动等),以保证瀑布流的高性能和流畅性。

gap
column
// 存储每列的当前累计高度,初始值为 0
const
new
Array
column
fill
0
// 遍历数据,逐个渲染元素
forEach
item =>
const
document
createElement
'div'
className
'waterfall-item'
innerHTML
`<img src="${item.imgUrl}" alt="${item.title}"><p>${item.title}</p>`
container
appendChild
// 设置元素宽度
style
width
`${itemWidth}px`
// 关键:找到当前高度最小的列的索引
const
indexOf
Math
min
// 关键:计算元素的 left 和 top 值
const
gap
const
// 设置元素定位
style
left
`${left}px`
style
top
`${top}px`
// 关键:更新该列的累计高度(当前元素高度 + 间距)
offsetHeight
gap
// 设置父容器高度为最高列的高度,避免父容器高度塌陷
container
style
height
`${Math.max(...columnHeights) - config.gap}px`

更多推荐文章

查看全部
  • Redis 核心数据结构与分布式锁实现详解
  • 零门槛理解大模型与深度学习基础概念
  • Java三件套:JDK、JRE、JVM详解
  • 荣耀发布 Robot Phone 与人形机器人,探索 AI 硬件生态新形态
  • 基于 AI 的全栈开发新路径:自动生成 UI 设计稿与 H5 原型
  • 人工智能在推荐系统中的应用与优化
  • AI 给产品经理带来的改变与未来展望
  • Linux 上部署 IgH EtherCAT 主站指南
  • Claude 官方技能文档:前端构建、Git 工作树、iOS 模拟与自动化
  • Spring 事务管理核心:@Transactional 注解与传播机制详解
  • Docker 镜像基础与操作详解
  • MySQL Windows 版安装与验证指南
  • 深度学习模型优化策略与实战调参
  • Linux 安装 Claude Code 并通过 VS Code SSH 远程集成
  • Stable Diffusion 视觉提示词注入攻击原理与实现分析
  • AI 热榜深度解析:平台生态、多智能体与评测体系的新风向
  • ChatGPT 技术能力、应用场景及商业化乱象分析
  • Linux 多机管理方案:禁用 root 密码与面板批量运维
  • Anaconda 安装与 Python 环境配置指南
  • 通义万相 2.1 模型升级解析与应用调优实践

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online